|
|
@@ -6,7 +6,7 @@
|
|
|
|
|
|
#### 爬虫的应用领域
|
|
|
|
|
|
-在理想的状态下,所有ICP(Internet Content Provider)都应该为自己的网站提供API接口来共享它们允许其他程序获取的数据,在这种情况下爬虫就不是必需品,国内比较有名的电商平台(如淘宝、京东等)、社交平台(如腾讯微博等)等网站都提供了自己的Open API,但是这类Open API通常会对可以抓取的数据以及抓取数据的频率进行限制。对于大多数的公司而言,及时的获取行业相关数据是企业生存的重要环节之一,然而大部分企业在行业数据方面的匮乏是其与生俱来的短板,合理的利用爬虫来获取数据并从中提取出有价值的信息是至关重要的。当然爬虫还有很多重要的应用领域,以下列举了其中的一部分:
|
|
|
+在理想的状态下,所有ICP(Internet Content Provider)都应该为自己的网站提供API接口来共享它们允许其他程序获取的数据,在这种情况下爬虫就不是必需品,国内比较有名的电商平台(如淘宝、京东等)、社交平台(如腾讯微博等)等网站都提供了自己的Open API,但是这类Open API通常会对可以抓取的数据以及抓取数据的频率进行限制。对于大多数的公司而言,及时的获取行业相关数据是企业生存的重要环节之一,然而大部分企业在行业数据方面的匮乏是其与生俱来的短板,合理的利用爬虫来获取数据并从中提取出有商业价值的信息是至关重要的。当然爬虫还有很多重要的应用领域,下面列举了其中的一部分:
|
|
|
|
|
|
1. 搜索引擎
|
|
|
2. 新闻聚合
|
|
|
@@ -90,7 +90,7 @@ Disallow: /
|
|
|
|
|
|
#### HTTP协议
|
|
|
|
|
|
-在开始讲解爬虫之前,我们稍微对HTTP(超文本传输协议)做一些回顾,因为我们在网页上看到的内容通常是浏览器执行HTML语言得到的结果,而HTTP就是传输HTML数据的协议。HTTP是构建于TCP(传输控制协议)之上应用级协议,它利用了TCP提供的可靠的传输服务实现了Web应用中的数据交换。按照维基百科上的介绍,设计HTTP最初的目的是为了提供一种发布和接收[HTML](https://zh.wikipedia.org/wiki/HTML)页面的方法,也就是说这个协议是浏览器和Web服务器之间传输的数据的载体。关于这个协议的详细信息以及目前的发展状况,大家可以阅读阮一峰老师的[《HTTP 协议入门》](http://www.ruanyifeng.com/blog/2016/08/http.html)、[《互联网协议入门》](http://www.ruanyifeng.com/blog/2012/05/internet_protocol_suite_part_i.html)系列以及[《图解HTTPS协议》](http://www.ruanyifeng.com/blog/2014/09/illustration-ssl.html)进行了解,下图是我在四川省网络通信技术重点实验室工作期间用开源协议分析工具Ethereal(抓包工具WireShark的前身)截取的访问百度首页时的HTTP请求和响应的报文(协议数据),由于Ethereal截取的是经过网络适配器的数据,因此可以清晰的看到从物理链路层到应用层的协议数据。
|
|
|
+在开始讲解爬虫之前,我们稍微对HTTP(超文本传输协议)做一些回顾,因为我们在网页上看到的内容通常是浏览器执行HTML语言得到的结果,而HTTP就是传输HTML数据的协议。HTTP和其他很多应用级协议一样是构建在TCP(传输控制协议)之上的,它利用了TCP提供的可靠的传输服务实现了Web应用中的数据交换。按照维基百科上的介绍,设计HTTP最初的目的是为了提供一种发布和接收[HTML](https://zh.wikipedia.org/wiki/HTML)页面的方法,也就是说这个协议是浏览器和Web服务器之间传输的数据的载体。关于这个协议的详细信息以及目前的发展状况,大家可以阅读阮一峰老师的[《HTTP 协议入门》](http://www.ruanyifeng.com/blog/2016/08/http.html)、[《互联网协议入门》](http://www.ruanyifeng.com/blog/2012/05/internet_protocol_suite_part_i.html)系列以及[《图解HTTPS协议》](http://www.ruanyifeng.com/blog/2014/09/illustration-ssl.html)进行了解,下图是我在四川省网络通信技术重点实验室工作期间用开源协议分析工具Ethereal(抓包工具WireShark的前身)截取的访问百度首页时的HTTP请求和响应的报文(协议数据),由于Ethereal截取的是经过网络适配器的数据,因此可以清晰的看到从物理链路层到应用层的协议数据。
|
|
|
|
|
|
HTTP请求(请求行+请求头+空行+[消息体]):
|
|
|
|
|
|
@@ -104,15 +104,15 @@ HTTP响应(响应行+响应头+空行+消息体):
|
|
|
|
|
|
#### 相关工具
|
|
|
|
|
|
-1. Chrome Developer Tools
|
|
|
+1. Chrome Developer Tools:谷歌浏览器内置的开发者工具。
|
|
|
|
|
|

|
|
|
|
|
|
-2. POSTMAN
|
|
|
+2. POSTMAN:功能强大的网页调试与RESTful请求工具。
|
|
|
|
|
|

|
|
|
|
|
|
-3. HTTPie
|
|
|
+3. HTTPie:命令行HTTP客户端。
|
|
|
|
|
|
```Shell
|
|
|
|
|
|
@@ -135,7 +135,7 @@ HTTP响应(响应行+响应头+空行+消息体):
|
|
|
X-Frame-Options: SAMEORIGIN
|
|
|
```
|
|
|
|
|
|
-4. BuiltWith:识别网站使用的技术
|
|
|
+4. BuiltWith:识别网站所用技术的工具。
|
|
|
|
|
|
```Python
|
|
|
|
|
|
@@ -150,7 +150,7 @@ HTTP响应(响应行+响应头+空行+消息体):
|
|
|
{'web-servers': ['Tengine'], 'web-frameworks': ['Twitter Bootstrap', 'Ruby on Rails'], 'programming-languages': ['Ruby']}
|
|
|
```
|
|
|
|
|
|
-5. python-whois:查询网站的所有者
|
|
|
+5. python-whois:查询网站所有者的工具。
|
|
|
|
|
|
```Python
|
|
|
|
|
|
@@ -160,7 +160,7 @@ HTTP响应(响应行+响应头+空行+消息体):
|
|
|
{'domain_name': ['BAIDU.COM', 'baidu.com'], 'registrar': 'MarkMonitor, Inc.', 'whois_server': 'whois.markmonitor.com', 'referral_url': None, 'updated_date': [datetime.datetime(2017, 7, 28, 2, 36, 28), datetime.datetime(2017, 7, 27, 19, 36, 28)], 'creation_date': [datetime.datetime(1999, 10, 11, 11, 5, 17), datetime.datetime(1999, 10, 11, 4, 5, 17)], 'expiration_date': [datetime.datetime(2026, 10, 11, 11, 5, 17), datetime.datetime(2026, 10, 11, 0, 0)], 'name_servers': ['DNS.BAIDU.COM', 'NS2.BAIDU.COM', 'NS3.BAIDU.COM', 'NS4.BAIDU.COM', 'NS7.BAIDU.COM', 'dns.baidu.com', 'ns4.baidu.com', 'ns3.baidu.com', 'ns7.baidu.com', 'ns2.baidu.com'], 'status': ['clientDeleteProhibited https://icann.org/epp#clientDeleteProhibited', 'clientTransferProhibited https://icann.org/epp#clientTransferProhibited', 'clientUpdateProhibited https://icann.org/epp#clientUpdateProhibited', 'serverDeleteProhibited https://icann.org/epp#serverDeleteProhibited', 'serverTransferProhibited https://icann.org/epp#serverTransferProhibited', 'serverUpdateProhibited https://icann.org/epp#serverUpdateProhibited', 'clientUpdateProhibited (https://www.icann.org/epp#clientUpdateProhibited)', 'clientTransferProhibited (https://www.icann.org/epp#clientTransferProhibited)', 'clientDeleteProhibited (https://www.icann.org/epp#clientDeleteProhibited)', 'serverUpdateProhibited (https://www.icann.org/epp#serverUpdateProhibited)', 'serverTransferProhibited (https://www.icann.org/epp#serverTransferProhibited)', 'serverDeleteProhibited (https://www.icann.org/epp#serverDeleteProhibited)'], 'emails': ['abusecomplaints@markmonitor.com', 'whoisrelay@markmonitor.com'], 'dnssec': 'unsigned', 'name': None, 'org': 'Beijing Baidu Netcom Science Technology Co., Ltd.', 'address': None, 'city': None, 'state': 'Beijing', 'zipcode': None, 'country': 'CN'}
|
|
|
```
|
|
|
|
|
|
-6. robotparser:解析robots.txt的工具
|
|
|
+6. robotparser:解析robots.txt的工具。
|
|
|
|
|
|
```Python
|
|
|
|
|
|
@@ -178,17 +178,21 @@ HTTP响应(响应行+响应头+空行+消息体):
|
|
|
|
|
|
### 一个简单的爬虫
|
|
|
|
|
|
-一个基本的爬虫通常分为数据采集(网页下载)、数据处理(网页解析)和数据存储(将有用的信息持久化)三个部分的内容,当然更为高级的爬虫在数据采集和处理时会使用并发编程或分布式技术,其中可能还包括调度器和后台管理程序(监控爬虫的工作状态以及检查数据抓取的结果)。
|
|
|
+一个基本的爬虫通常分为数据采集(网页下载)、数据处理(网页解析)和数据存储(将有用的信息持久化)三个部分的内容,当然更为高级的爬虫在数据采集和处理时会使用并发编程或分布式技术,这就需要有调度器(安排线程或进程执行对应的任务)、后台管理程序(监控爬虫的工作状态以及检查数据抓取的结果)等的参与。
|
|
|
|
|
|

|
|
|
|
|
|
-1. 设定抓取目标(种子页面)并获取网页。
|
|
|
-2. 当服务器无法访问时,设置重试次数。
|
|
|
-3. 在需要的时候设置用户代理(否则无法访问页面)。
|
|
|
-4. 对获取的页面进行必要的解码操作。
|
|
|
-5. 通过正则表达式获取页面中的链接。
|
|
|
+一般来说,爬虫的工作流程包括以下几个步骤:
|
|
|
+
|
|
|
+1. 设定抓取目标(种子页面/起始页面)并获取网页。
|
|
|
+2. 当服务器无法访问时,按照指定的重试次数尝试重新下载页面。
|
|
|
+3. 在需要的时候设置用户代理或隐藏真实IP,否则可能无法访问页面。
|
|
|
+4. 对获取的页面进行必要的解码操作然后抓取出需要的信息。
|
|
|
+5. 在获取的页面中通过某种方式(如正则表达式)抽取出页面中的链接信息。
|
|
|
6. 对链接进行进一步的处理(获取页面并重复上面的动作)。
|
|
|
-7. 将有用的信息进行持久化(以备后续的处理)。
|
|
|
+7. 将有用的信息进行持久化以备后续的处理。
|
|
|
+
|
|
|
+下面的例子给出了一个从“搜狐体育”上获取NBA新闻标题和链接的爬虫。
|
|
|
|
|
|
```Python
|
|
|
|
|
|
@@ -248,6 +252,7 @@ def start_crawl(seed_url, match_pattern, *, max_depth=-1):
|
|
|
current_url = url_list.pop(0)
|
|
|
depth = visited_url_list[current_url]
|
|
|
if depth != max_depth:
|
|
|
+ # 尝试用utf-8/gbk/gb2312三种字符集进行页面解码
|
|
|
page_html = get_page_html(current_url, charsets=('utf-8', 'gbk', 'gb2312'))
|
|
|
links_list = get_matched_parts(page_html, match_pattern)
|
|
|
param_list = []
|
|
|
@@ -280,15 +285,19 @@ if __name__ == '__main__':
|
|
|
|
|
|
```
|
|
|
|
|
|
-注意事项:
|
|
|
+由于使用了MySQL实现持久化操作,所以要先启动MySQL服务器再运行该程序。
|
|
|
+
|
|
|
+### 爬虫注意事项
|
|
|
+
|
|
|
+通过上面的例子,我们对爬虫已经有了一个感性的认识,在编写爬虫时有以下一些注意事项:
|
|
|
|
|
|
-1. 处理相对链接。有的时候我们从页面中获取的链接不是一个完整的绝对链接而是一个相对链接,这种情况下需要将其与URL前缀进行拼接(urllib.parse中的urljoin函数可以完成此项操作)。
|
|
|
+1. 处理相对链接。有的时候我们从页面中获取的链接不是一个完整的绝对链接而是一个相对链接,这种情况下需要将其与URL前缀进行拼接(`urllib.parse`中的`urljoin()`函数可以完成此项操作)。
|
|
|
|
|
|
-2. 设置代理服务。有些网站会限制访问的区域(例如美国的Netflix屏蔽了很多国家的访问),有些爬虫需要隐藏自己的身份,在这种情况下可以设置代理服务器(urllib.request中的ProxyHandler就是用来进行此项操作)。
|
|
|
+2. 设置代理服务。有些网站会限制访问的区域(例如美国的Netflix屏蔽了很多国家的访问),有些爬虫需要隐藏自己的身份,在这种情况下可以设置使用代理服务器,代理服务器有免费(如[西刺代理](http://www.xicidaili.com/)、[快代理](https://www.kuaidaili.com/free/))和付费两种(如[讯代理](http://www.xdaili.cn/)、[阿布云代理](https://www.abuyun.com/)),付费的一般稳定性和可用性都更好,可以通过`urllib.request`中的`ProxyHandler`来为请求设置代理。
|
|
|
|
|
|
3. 限制下载速度。如果我们的爬虫获取网页的速度过快,可能就会面临被封禁或者产生“损害动产”的风险(这个可能会导致吃官司且败诉),可以在两次下载之间添加延时从而对爬虫进行限速。
|
|
|
|
|
|
-4. 避免爬虫陷阱。有些网站会动态生成页面内容,这会导致产生无限多的页面(例如在线万年历等)。可以通过记录到达当前页面经过了多少个链接(链接深度)来解决该问题,当达到事先设定的最大深度时爬虫就不再像队列中添加该网页中的链接了。
|
|
|
+4. 避免爬虫陷阱。有些网站会动态生成页面内容,这会导致产生无限多的页面(例如在线万年历通常会有无穷无尽的链接)。可以通过记录到达当前页面经过了多少个链接(链接深度)来解决该问题,当达到事先设定的最大深度时爬虫就不再像队列中添加该网页中的链接了。
|
|
|
|
|
|
5. SSL相关问题。在使用`urlopen`打开一个HTTPS链接时会验证一次SSL证书,如果不做出处理会产生错误提示“SSL: CERTIFICATE_VERIFY_FAILED”,可以通过以下两种方式加以解决:
|
|
|
|