python网络数据采集1

文章目录

python网络数据采集代码(github)

python代码简洁,拥有高级数据结构,能够以简单高效的方式执行面向对象编程,但是它的运行效率受人诟病,所以python经常作为一种“胶水语言”,把耗时的核心部分使用C/C++等效率更高的语言编写,然后再由python粘和。事实上,在大多数数据任务上,python的运行效率已经可以媲美C/C++.

在大数据深入人心的时代,网络数据采集作为网络、数据库、和机器学习等领域的交汇点,成为满足个性化网络数据需求的最佳实践。网络数据采集技术可以进一步精炼数据,把网络上杂乱无章的的数据聚合成规范的形式,方便分析和挖掘。

工作中经常会遇到各种数据,比如几百页的数据,或者在数据杂乱无章的网站中充满着带有陷阱的表单和坑爹的验证码,甚至需要的数据保存在网页版的PDF和网络图片中。你需要了解常用的数据采集手段和网络表单安全措施。

网络数据采集可以使用多种语言,比如:python, java ,php, C#, Go都可以。Python拥有简洁轻松的语法,开箱可用的模块,强大快乐的社区,总可以快速构建出简单高效的解决方案。

网络数据采集是涉及多个领域的:

Python数据采集的模块有:urllib, BeautifulSoup, lxml, Scrapy, PdfMiner, Requests, Selenium, NLTK, Pillow, unittest,Pysocks等
还有一些知名网站的API,MySQL数据库,OpenRefine数据分析工具,PhanthomJS无头浏览器以及Tor代理服务器等内容。

1
如果需要了解python多进程(multiprocessing),并发(concurrency),集群(cluster)等高性能和多核编程,可以移步python高性能、多核编程、设计模式的书籍。

进行网络数据采集时,要控制网络数据采集的速度,降低被采集网站服务器的负担。

什么是网络数据采集

网络数据采集也称 网页抓屏(screen scraping),数据挖掘(data mining), 网络收割(Web harvesting),或者网络机器人(bots)。
网络数据采集是通过多种手段收集网络数据的方式,涉及数据库,网络服务器,HTTP协议,HTML语言,网络安全,图像处理,数据科学等。
网络数据采集不光是通过与API交互(或者与浏览器进行交互)的方式,还需要处理js,多媒体和cookie的新式网站。最常用的方法是写一个自动化程序向网络服务器请求数据(通常是HTML表单或其他网页文件),然后对数据进行解析,提取需要的信息。

网络数据挖掘流程:采集数据 -> 数据清洗 ->挖掘模型构建 -> 归类展示(可视化)
数据采集的可视化; 爬取数据 ->存入数据库 ->调用数据库将数据可视化

网络爬虫可以完成传统搜索引擎不能做的事情,搜索引擎不能填写表单,比如爬取大量网站的数据查询出航班价格随时间变化的图表,爬虫可以一次可以成千上百万个网页。

存在各种API(Twitter或者维基百科的API),可以向用户提供服务器中格式完好的数据,而且一个API提供了不同的数据类型,在某些时候API是比爬虫获取数据更加方便。但是在:

  • 你收集的数据来自不同的网站,没有一个API能够综合多个网站的数据。
  • 你采取的数据非常小众,网站不会为你单独做一个api
  • 一些网站没有基础设施或者技术能力去建API
  • 即使API存在,有时候还会有请求内容和次数限制,API提供的数据类型或者数据格式也可能无法满足需求

大多数的应用场景都会用到这样毫无阻碍获取数据的手段:市场预测,机器语言翻译,甚至医疗诊断领域,通过对新闻网站、文章以及健康论坛中的数据进行采集和分析,也可以获取很多好处。无论处于哪个领域,网络数据采集都会让你的工作更加高效,提升生产力,甚至开创一个全新的领域。

初见网络爬虫

基本原理:如何利用Python从服务器请求信息,如何对服务器的响应进行基本处理,如何利用自动化手段与网站进行交互。最终你将创建出具有域名切换、信息收集、信息存储功能的爬虫。
爬虫的基本想法:

  • 通过域名获取网站HTML数据
  • 根据目标信息解析数据
  • 存储目标信息
  • 如果需求,移动到下一个页面重复这个过程
网络连接
get,post请求的区别

HTTP从网络服务获取信息有4种方式:

  • GET: 一般指在浏览器中输入url(不含参数),服务器返回信息的方式
  • POST:当你填写表单或者提交信息到网络服务器后端程序时使用。比如:你登录网站时,就是通过用户名和密码(有可能通过加密)发起一个POST请求。
  • PUT: 在网站交互的过程中不常用,在API请求有时使用。PUT请求用来更新一个对象或信息。比如:更新一个老用户的邮箱。现在好多API更新信息都使用POST替代PUT,这取决与API请求本身是如何构建的。
  • DELETE:用于删除一个对象。比如我们向http://myapi.com/user/23发起一个DELETE请求,就会删除ID号是23的用户。DELETE在公用API不常用,不能随便让一个用户删除数据库的信息。

SSL和SSH

++SSH外链++
SSH:安全外壳协议(SSH)是一种在不安全网络上提供安全远程登录及其它安全网络服务的协议。Secure Shell,又可记为SSH

++SSL外链++
++SSL外链2++
OpenSSL 是一个强大的安全套接字层密码库,Apache 使用它加密 HTTPS,OpenSSH 使用它加密SSH,但是,你不应该只将其作为一个库来使用,它还是一个多用途的、跨平台的密码工具。

多多使用知乎,google,百度是个坑
http 和 https 有何区别?如何灵活使用?


关于url中# #! ? &的作用:

# 代表锚点,可以跳转到页面指定的位置,#后面的内容称为hashtag, hashtag多用于AJAX请求获取数据。
如果进行url请求,修改#后面的内容,浏览器不会向服务器重新加载index.html,既不会重新加载,但是会在浏览器中增加一条历史记录
window.location.hash读取hashtag,这是一个可读可写的变量,用于判断网页状态是否改变,增加一条访问记录。

AJAX = JAVASCRIPT + XML
AJAX是一种用于创建快速动态网页的技术

?在url中有两种作用:

  1. 连接作用,连接网址和参数,比如:http://www.baidu.com/?userid=walkk&password=123456
  2. 清楚缓存: index.html?test123123,表示不调用缓存,认为是新地址重新加载。

&就是上文中的,间隔参数的作用

GET方法向服务器请求数据的过程
  1. A电脑发送一串0、1的比特值,这些比特构成了一种信息,包括请求头和消息体。请求头包括了A本地路由的MAC地址和服务器B的IP地址,消息体包含了A对B服务器的请求内容。
  2. A的路由器收到所有0、1比特值,把它理解成一个数据包(package),从A的MAC地址寄到B的IP的地址,A的路由器将数据包加上自己的IP地址作为“发件地址”,然后通过互联网发出去
  3. A的数据包经过了一些中介服务器,沿着正确的物理/电路路径前进,到达了B的服务器
  4. B的服务器收取到数据包,解析请求头里面的目标端口(通常是网络应用的80端口,IP地址相当于街道地址,端口相当于房间号),把数据包传到网络服务器对应的应用上。
  5. 服务器应用从服务器处理器器收到一串数据,
    • 这是一个GET请求
    • 请求文件Indx.html
  6. 网络服务器应用找到对应的HTML文件,把它打成数据包,通过本地的路由器回传到B服务器上。
BeautifulSoup

使用urlopen()获取HTML数据,然后把HTML数据传到BeautifulSoup对象,转换成(树型的类似XML结构)下面的结构:

1
2
3
4
**html**            ->    <html><head>.....</head><body></body></html>
**head** -> <head><title>....</title></head>

**body** -> <body><h1>An Int...</h1><div>Loren ip....</div></body>

1
2
3
4
5
6
7
8
9
10
11
12
13
from urllib.request import urlopen
from bs4 import BeautifulSop

url = "www.baidu.com"
html = urlopen(url)
bsobj = BeautifulSop(html.read())
print(bsobj.h1)
'''
这里访问的是html下body中第一个h1
bsobj.h1 通过对象名获取节点属性
bsobj.h1 = bsobj.html.h1 = bsobj.body.h1
一般很少使用,使用正则或Beautiful中的find(),findAll()过滤标签
'''

网络数据采集添加 异常处理 (Important)

网络数据采集会遇到:网页数据格式不友好,网站服务器怠机,目标数据的标签找不到等等问题,添加异常处理try….. except防止程序奔溃,死循环,增加健壮性。

html = ulropen("www.jianshu.com")
就像请求数据会出现两种异常:

  • 目标网页在服务器上不存在(或获取页面的过程中出错)
  • 服务器不存在

第一种异常发 生, 会返回HTTP错误,比如404 Page Not Found, 500 Internal Server Error,所有类似的异常,urlopen都会返回HTTPError

1
2
3
4
5
6
7
8
try:
html = urlopen("www.jianshu.com")
except HTTPError as e:
print(e)

else:
#程序继续,如果在上面的try...except捕捉异常中返回或
#break中断,不需要else语句,else内容也不执行

第二种情况,服务器不存在(url不存在或者写错了),urlopen会返回一个None对象

1
2
3
4
if html is None:       # 注意是urlopen返回的None对象
print("URL Not Found")
else:
程序继续

如果调用Beautiful对象标签,增加一个判断条件判断标签是否存在,不存在返回None对象。但是如果继续访问None对象下面的子标签就会返回一个AttributeError
如何对这两种情形做出检查:

1
2
3
4
5
6
7
8
9
try:
badcontent = bsobj.nonExistingTag.subTag
except AttributeError as e:
print("Tag not Found")
else:
if badcontent is None:
print("Tag not Found")
else:
print(badcontent)

写爬虫的时候,思考代码总体格局大专栏  python网络数据采集1ong>,既容易捕捉异常,又方便阅读。
为了重用代码:多写getSiteHtml(),和getTitle()这种通用函数(具有周密的异常处理功能,修改函数内容别人就可以调用),进行快速稳定的网络采集。

复杂HTML解析 + 使用爬虫的几种方式

解决复杂HTML页面需要考虑的问题:

  • 寻找是否有HTML页面样式更加友好的移动版
  • 寻找隐藏在JS中的内容
  • URL链接有时候能直接提取出title标题
  • 寻求多个数据源看是否有相同数据

在面对埋藏很深或格式不友好的数据,千万不要不经过思考就写代码。

添加异常捕获

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
from urllib.request import urlopen
from bs4 import BeautifulSoup

'''
__title__ = ''
__author__ = 'walsky'
__mtime__ = '2016.10.30'
__email__ = 'wal139491@163.com'
# code is far away from bugs with the god animal protecting
I love animals. They taste delicious.
┏┓ ┏┓
┏┛┻━━━┛┻┓
┃ ☃ ┃
┃ ┳┛ ┗┳ ┃
┃ ┻ ┃
┗━┓ ┏━┛
┃ ┗━━━┓
┃ 神兽保佑 ┣┓
┃ 永无BUG! ┏┛
┗┓┓┏━┳┓┏┛
┃┫┫ ┃┫┫
┗┻┛ ┗┻┛
'''

def (Url):
try:
html = urlopen(url)
except HttPError as e:
print(e)
else:
getTitle(html)
def getTitle(html):
if html is None:
print("Url Not Found")
else:
try:
bsobj = BeautifulSoup(html)
title = bsobj.html.title
except AttributeError as e:
print("Title not found")
else:
if title is None:
print("title not found")
else:
print(title)

if __name__ == '__main__':
getSiteHtml("www.jianshu.com")

BeautifulSoup

BeautifulSoup有四个对象:
Tag(标签里面有name,attrs)
获取标签name, attrs[]
bsobj.p.name bsobj.p.attrs[]
单独获得某个属性值 :
bsobj.a['href'] bsobj.a.get('href')

BeautifulSoup对象(bsobj)
bsobj = BeautifulSoup(html)

NavigableString
(标签中的文字比如<p>标签中的文字</p>)
p.string 就可以获得标签中的文字

Comment 获得html的注释内容 <!--注释-->
<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
利用 .string 来输出它的内容,它已经把注释符号去掉了,我们获取其中内容需要做一下判断:
if type(soup.a.string)==bs4.element.Comment: print soup.a.string

具体使用方法

  1. bsobj.h1 bsobj.a bsobj.p
    查找的是在所有内容中的第一个符合要求的标签

  2. bsobj.find() 和bsobj.findall() 方法
    find()和findAll(),都有过滤标签作用,最后返回的一个标签列表,就像<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a> 完整的标签

由于返回的是一个列表,要想得到其中内容1.使用for 循环遍历列表2.使用get_text()方法去除html的标签
nameList = bsobj.findAll(“span”,{“class”:{“red”,”blue”}})
for content in nameList:
content.get_text()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

findAll(tag, attributes, recursive, text, limit, keywords)

# tag 传入一个标签名,或多个标签名组成的列表
findAll("h1") 或 findAll({"h1","h2","p","a"})
最后以列表返回 h1,h1,p,a 的多个标签
# attributes 用Python字典封装若干 属性+属性值
findAll("span",{"class":"red","green"})
# recursive 布尔变量,ture查找所有子标签,false只查找一级子标签
一般不需要设置
# text 使用标签中的内容进行匹配 <p>这是标签内容</p>
nameList =bsobj.findAll(text="i love python")
print(len(nameList))
# limit 限制列表的获取几项
findAll("p",limit =7)
# keyword 也就是使用'=' 指定标签的具体属性
content = findAll(id="content")
print(content[0].get_text())
'''其实:findAll(id="foot") = findAll("",{"id" : "foot"}) #不指定标签名
但你不能使用:findAll(class="green") 因为class是python的保留字
可以:findAll(_class="green") 或findAll("",{"class":"green"})
'''

find(tag, attributes, recursive, text, limit, keywords)少了limit属性,基本使用方法相同

导航树

++参考外链++
其实就是使用文档结构获取:
tr是table标签的子标签, children
tr,th,td,img,span是table标签的后代标签 descendants

1
2
3
4
5
6
7
8
for child in bsobj.findAll("table",{"id":"giftshit"}).children():
print(child)
#就会打出giftshift表格的所有数据行

for child in bsobj.findAll("table",{"id":"giftshit"}).tr.next_siblings:
print(child)
#就会打出giftshift表格的除了第一行所有数据行
#或者使用previous_siblings

正则和BeautifulSoup的结合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import re
from bs4 import BeautifulSoup
from urllib.request import urlopen

html = urlopen("www.jianshu.com")
bsobj = BeautifulSoup(html)
imgs = bsobj.findAll("img",{"src":re.compile("../imgimg.*.jpg")})
'''
查找a标签,都在id为bodyContent的div中,都以"/wiki/"开头
url链接中不含":"
'''

links = bsobj.find("div",{"id":"bodyContent"}).findAll("a",{"href":re.compile(
"^(/wiki/)((?!:).)*$")})
#((?!.)*)括号编组这样就任何地方都不会出现:
for img in imgs:
print(img["src"]) #使用attrs获取图片的相对路径,获取属性
print(img.get_text()) #使用get_text获取img的内容
'''
<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
如果提取<a 标签属性>,a.attrs["herf"]或a["href"]都行
如果提取<a>标签内容,a.get_text()
'''

使用lambda函数替代正则

Beautiful允许我们把lambda函数作为findAll()的参数,限制条件是:

  1. 必须把一个标签作为参数
  2. 返回结果是bool形式
1
2
3
bsobj.findAll(lambda tag: len(tag.attrs == 2))
# 返回只有两个属性的标签列表
# 考虑使用,简洁快速最重要

关于python的html解析库:

  • BeautifulSoup不用介绍了
  • lxml,这个库可以用来解析Html和XML文档,大部分源码用C实现,以非常底层的实现而闻名。虽然学习需要花一些时间,但在处理大多数HTML文档速度都比较快。
  • HTML parser 这是Python自带的解析库
原文地址:https://www.cnblogs.com/lijianming180/p/12432988.html