11# Python入门网络爬虫之精华版
22
3+ #### Author: LiNing
4+
5+ #### Email: lining0806@gmail.com
6+
7+ #### Blog: [ 宁哥的小站] ( http://www.lining0806.com/ )
8+
9+ ***
10+
311Python学习网络爬虫主要分3个大的版块:** 抓取** ,** 分析** ,** 存储**
4- 另外,比较常用的爬虫框架[ Scrapy] ( http://scrapy.org/ ) ,这里最后也介绍一下。
5- 先列举一下相关参考:[ 宁哥的小站-网络爬虫] ( http://www.lining0806.com/category/spider/ )
12+
13+ 另外,比较常用的爬虫框架[ Scrapy] ( http://scrapy.org/ ) ,这里最后也详细介绍一下。
14+
15+ 首先列举一下本人总结的相关文章,这些覆盖了入门网络爬虫需要的基本概念和技巧:[ 宁哥的小站-网络爬虫] ( http://www.lining0806.com/category/spider/ )
616***
717
18+ 当我们在浏览器中输入一个url后回车,后台会发生什么?比如说你输入[ http://www.lining0806.com/ ] ( http://www.lining0806.com/ ) ,你就会看到宁哥的小站首页。
19+
20+ 简单来说这段过程发生了以下四个步骤:
21+
22+ * 查找域名对应的IP地址。
23+ * 向IP对应的服务器发送请求。
24+ * 服务器响应请求,发回网页内容。
25+ * 浏览器解析网页内容。
26+
27+ 网络爬虫要做的,简单来说,就是实现浏览器的功能。通过指定url,直接返回给用户所需要的数据,而不需要一步步人工去操纵浏览器获取。
28+
829## 抓取
9- 这一步,你要明确要得到的内容是是什么?是HTML源码,还是Json格式的字符串等等 。
30+ 这一步,你要明确要得到的内容是是什么?是HTML源码,还是Json格式的字符串等 。
1031
1132#### 1. 最基本的抓取
12- 一般属于get请求情况,直接从服务器上获取数据。
33+
34+ 抓取大多数情况属于get请求,即直接从对方服务器上获取数据。
35+
1336首先,Python中自带urllib及urllib2这两个模块,基本上能满足一般的页面抓取。另外,[ requests] ( https://github.com/kennethreitz/requests ) 也是非常有用的包,与此类似的,还有[ httplib2] ( https://github.com/jcgregorio/httplib2 ) 等等。
37+
1438```
1539Requests:
1640 import requests
1741 response = requests.get(url)
18- content = requests.get(url).content # string
19- print "response headers:", response.headers # dict
42+ content = requests.get(url).content
43+ print "response headers:", response.headers
2044 print "content:", content
2145Urllib2:
2246 import urllib2
2347 response = urllib2.urlopen(url)
24- content = urllib2.urlopen(url).read() # string
25- print "response headers:", response.headers # not dict
48+ content = urllib2.urlopen(url).read()
49+ print "response headers:", response.headers
2650 print "content:", content
2751Httplib2:
2852 import httplib2
2953 http = httplib2.Http()
3054 response_headers, content = http.request(url, 'GET')
31- print "response headers:", response_headers # dict
55+ print "response headers:", response_headers
3256 print "content:", content
3357```
58+
3459此外,对于带有查询字段的url,get请求一般会将来请求的数据附在url之后,以?分割url和传输数据,多个参数用&连接。
60+
3561```
36- data = {'data1':'XXXXX', 'data2':'XXXXX'} # dict类型
62+ data = {'data1':'XXXXX', 'data2':'XXXXX'}
3763Requests:data为dict,json
3864 import requests
39- response = requests.get(url=url, params=data) # GET请求发送
65+ response = requests.get(url=url, params=data)
4066Urllib2:data为string
4167 import urllib, urllib2
42- data = urllib.urlencode(data) # 编码工作,由dict转为string
43- full_url = url+'?'+data # GET请求发送
68+ data = urllib.urlencode(data)
69+ full_url = url+'?'+data
4470 response = urllib2.urlopen(full_url)
4571```
4672
47- ### 2. 对于反爬虫机制的处理
73+ ### 2. 对于登陆情况的处理
74+
75+ ** 2.1 使用表单登陆**
76+
77+ 这种情况属于post请求,即先向服务器发送表单数据,服务器再将返回的cookie存入本地。
4878
49- ** 2.1 模拟登陆情况**
50- 这种属于post请求情况,先向服务器发送表单数据,服务器再将返回的cookie存入本地。
5179```
52- data = {'data1':'XXXXX', 'data2':'XXXXX'} # dict类型
80+ data = {'data1':'XXXXX', 'data2':'XXXXX'}
5381Requests:data为dict,json
5482 import requests
55- response = requests.post(url=url, data=data) # POST请求发送,可用于用户名密码登陆情况
83+ response = requests.post(url=url, data=data)
5684Urllib2:data为string
5785 import urllib, urllib2
58- data = urllib.urlencode(data) # 编码工作,由dict转为string
59- req = urllib2.Request(url=url, data=data) # POST请求发送,可用于用户名密码登陆情况
86+ data = urllib.urlencode(data)
87+ req = urllib2.Request(url=url, data=data)
6088 response = urllib2.urlopen(req)
6189```
6290
63- ** 2.2 使用cookie登陆情况**
91+ ** 2.2 使用cookie登陆**
92+
6493使用cookie登陆,服务器会认为你是一个已登陆的用户,所以就会返回给你一个已登陆的内容。因此,需要验证码的情况可以使用带验证码登陆的cookie解决。
94+
6595```
6696import requests
67- requests_session = requests.session() # 创建会话对象requests.session(),可以记录cookie
68- response = requests_session.post(url=url_login, data=data) # requests_session的POST请求发送,可用于用户名密码登陆情况。必须要有这一步!拿到Response Cookie!
97+ requests_session = requests.session()
98+ response = requests_session.post(url=url_login, data=data)
6999```
100+
70101若存在验证码,此时采用response = requests_session.post(url=url_login, data=data)是不行的,做法应该如下:
102+
71103```
72104response_captcha = requests_session.get(url=url_login, cookies=cookies)
73105response1 = requests.get(url_login) # 未登陆
74106response2 = requests_session.get(url_login) # 已登陆,因为之前拿到了Response Cookie!
75107response3 = requests_session.get(url_results) # 已登陆,因为之前拿到了Response Cookie!
76108```
109+
77110相关参考:[ 网络爬虫-验证码登陆] ( http://www.lining0806.com/6-%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB-%E9%AA%8C%E8%AF%81%E7%A0%81%E7%99%BB%E9%99%86/ )
111+
78112参考项目:[ 爬取知乎网站] ( https://github.com/lining0806/ZhihuSpider )
79113
80- ** 2.3 伪装成浏览器,或者反“反盗链”**
81- ```
82- headers = {'User-Agent':'XXXXX'} # 伪装成浏览器访问,适用于拒绝爬虫的网站
83- headers = {'Referer':'XXXXX'} # 反“反盗链”,适用于有“反盗链”的网站
84- headers = {'User-Agent':'XXXXX', 'Referer':'XXXXX'}
85- Requests:
86- response = requests.get(url=url, headers=headers)
87- Urllib2:
88- import urllib, urllib2
89- req = urllib2.Request(url=url, headers=headers)
90- response = urllib2.urlopen(req)
91- ```
114+ ### 3. 对于反爬虫机制的处理
115+
116+ ** 3.1 使用代理**
92117
93- ### 3. 使用代理
94118适用情况:限制IP地址情况,也可解决由于“频繁点击”而需要输入验证码登陆的情况。
119+
120+ 这种情况最好的办法就是维护一个代理IP池,网上有很多免费的代理IP,良莠不齐,可以通过筛选找到能用的。对于“频繁点击”的情况,我们还可以通过限制爬虫访问网站的频率来避免被网站禁掉。
121+
95122```
96123proxies = {'http':'http://XX.XX.XX.XX:XXXX'}
97124Requests:
@@ -105,7 +132,37 @@ Urllib2:
105132 response = urllib2.urlopen(url)
106133```
107134
135+ ** 3.2 时间设置**
136+
137+ 适用情况:限制频率情况。
138+
139+ Requests,Urllib2都可以使用time库的sleep()函数:
140+
141+ ```
142+ import time
143+ time.sleep(1)
144+ ```
145+
146+ ** 3.3 伪装成浏览器,或者反“反盗链”**
147+
148+ 有些网站会检查你是不是真的浏览器访问,还是机器自动访问的。这种情况,加上User-Agent,表明你是浏览器访问即可。有时还会检查是否带Referer信息还会检查你的Referer是否合法,一般再加上Referer。
149+
150+ ```
151+ headers = {'User-Agent':'XXXXX'} # 伪装成浏览器访问,适用于拒绝爬虫的网站
152+ headers = {'Referer':'XXXXX'}
153+ headers = {'User-Agent':'XXXXX', 'Referer':'XXXXX'}
154+ Requests:
155+ response = requests.get(url=url, headers=headers)
156+ Urllib2:
157+ import urllib, urllib2
158+ req = urllib2.Request(url=url, headers=headers)
159+ response = urllib2.urlopen(req)
160+ ```
161+
108162### 4. 对于断线重连
163+
164+ 不多说。
165+
109166```
110167def multi_session(session, *arg):
111168 while True:
@@ -117,7 +174,9 @@ def multi_session(session, *arg):
117174 print '.',
118175 retryTimes -= 1
119176```
177+
120178或者
179+
121180```
122181def multi_open(opener, *arg):
123182 while True:
@@ -129,39 +188,72 @@ def multi_open(opener, *arg):
129188 print '.',
130189 retryTimes -= 1
131190```
191+
132192这样我们就可以使用multi_session或multi_open对爬虫抓取的session或opener进行保持。
133193
134194### 5. 多进程抓取
135- 这里针对[ 华尔街见闻] ( http://live.wallstreetcn.com/ ) 进行多进程的实验对比:[ Python多进程抓取] ( https://github.com/lining0806/Spider_Python ) 与 [ Java多进程抓取] ( https://github.com/lining0806/Spider )
195+
196+ 这里针对[ 华尔街见闻] ( http://live.wallstreetcn.com/ ) 进行多进程抓取的实验对比:[ Python多进程抓取] ( https://github.com/lining0806/Spider_Python ) 与 [ Java多进程抓取] ( https://github.com/lining0806/Spider )
197+
136198相关参考:[ 关于Python和Java的多进程多线程计算方法对比] ( http://www.lining0806.com/%E5%85%B3%E4%BA%8Epython%E5%92%8Cjava%E7%9A%84%E5%A4%9A%E8%BF%9B%E7%A8%8B%E5%A4%9A%E7%BA%BF%E7%A8%8B%E8%AE%A1%E7%AE%97%E6%96%B9%E6%B3%95%E5%AF%B9%E6%AF%94/ )
137199
138200### 6. 对于Ajax请求的处理
139- 对于“加载更多”情况,使用Ajax来传输很多数据。它的工作原理是:从网页的url加载网页的源代码之后,会在浏览器里执行JavaScript程序。这些程序会加载更多的内容,“填充”到网页里。这就是为什么如果你直接去爬网页本身的url,你会找不到页面的实际内容。
201+
202+ 对于“加载更多”情况,使用Ajax来传输很多数据。
203+
204+ 它的工作原理是:从网页的url加载网页的源代码之后,会在浏览器里执行JavaScript程序。这些程序会加载更多的内容,“填充”到网页里。这就是为什么如果你直接去爬网页本身的url,你会找不到页面的实际内容。
205+
140206这里,若使用Google Chrome分析”请求“对应的链接(方法:右键→审查元素→Network→清空,点击”加载更多“,出现对应的GET链接寻找Type为text/html的,点击,查看get参数或者复制Request URL),循环过程。
207+
141208* 如果“请求”之前有页面,依据上一步的网址进行分析推导第1页。以此类推,抓取抓Ajax地址的数据。
142209* 对返回的json格式数据(str)进行正则匹配。json格式数据中,需从'\\ uxxxx'形式的unicode_escape编码转换成u'\uxxxx'的unicode编码。
143- 参考项目:[ Python多进程抓取] ( https://github.com/lining0806/Spider_Python )
144210
145- ### 7. 验证码识别
211+ ### 7. 自动化测试工具Selenium
212+
213+ Selenium是一款自动化测试工具。它能实现操纵浏览器,包括字符填充、鼠标点击、获取元素、页面切换等一系列操作。总之,凡是浏览器能做的事,Selenium都能够做到。
214+
215+ 这里我列出在给定城市列表后,使用selenium来动态抓取[ 去哪儿网] ( http://flight.qunar.com/ ) 的票价信息的代码。
216+
217+ 相关参考:[ 网络爬虫之Selenium使用代理登陆:爬取去哪儿网站] ( https://github.com/lining0806/QunarSpider )
218+
219+ ### 8. 验证码识别
220+
146221对于网站有验证码的情况,我们有三种办法:
147222
148- 1 . 使用代理,更新IP。
149- 2 . 使用cookie登陆。
150- 3 . 验证码识别。
223+ * 使用代理,更新IP。
224+ * 使用cookie登陆。
225+ * 验证码识别。
151226
152227使用代理和使用cookie登陆之前已经讲过,下面讲一下验证码识别。
228+
153229可以利用开源的Tesseract-OCR系统进行验证码图片的下载及识别,将识别的字符传到爬虫系统进行模拟登陆。如果不成功,可以再次更新验证码识别,直到成功为止。
230+
154231参考项目:[ Captcha1] ( https://github.com/lining0806/Captcha1 )
155232
233+ ** 爬取还有一个需要注意的问题:**
234+ * 如何监控一系列网站的更新情况,也就是说,如何进行增量式爬取?
156235
157236## 分析
237+
158238抓取之后就是对抓取的内容进行分析,你需要什么内容,就从中提炼出相关的内容来。
239+
159240常见的分析工具有[ 正则表达式] ( http://deerchao.net/tutorials/regex/regex.htm ) ,[ BeautifulSoup] ( http://www.crummy.com/software/BeautifulSoup/ ) ,[ lxml] ( http://lxml.de/ ) 等等。
160241
161242## 存储
243+
162244分析出我们需要的内容之后,接下来就是存储了。
163- 我们可以选择存入文本文件,也可以选择存入MySQL或MongoDB数据库等。
245+
246+ 我们可以选择存入文本文件,也可以选择存入[ MySQL] ( http://www.mysql.com/ ) 或[ MongoDB] ( https://www.mongodb.org/ ) 数据库等。
247+
248+ ** 存储有两个需要注意的问题:**
249+
250+ * 以什么形式存储?
251+ * 如何进行内容去重?
164252
165253## Scrapy
254+
166255Scrapy是一个基于Twisted的开源的Python爬虫框架,在工业中应用非常广泛。
167- 相关内容可以参考[ 基于Scrapy网络爬虫的搭建] ( http://www.lining0806.com/%E5%9F%BA%E4%BA%8Escrapy%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB%E7%9A%84%E6%90%AD%E5%BB%BA/ )
256+
257+ 相关内容可以参考[ 基于Scrapy网络爬虫的搭建] ( http://www.lining0806.com/%E5%9F%BA%E4%BA%8Escrapy%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB%E7%9A%84%E6%90%AD%E5%BB%BA/ ) ,同时我给出这篇文章介绍的[ 微信搜索] ( http://weixin.sogou.com/weixin ) 爬取的项目代码,给大家作为学习参考。
258+
259+ 参考项目:[ 使用Scrapy或Requests递归抓取微信搜索结果] ( https://github.com/lining0806/WechatSearchProjects )
0 commit comments