对于很多简单页面,厌倦了一行一行自己写爬虫,所以尝试一下 Scrapy。重点考察
- 开发效率
- 异常处理
- 防封机制
使用教程参考官网 scrapy.org, 写得很细致。
安装 Scrapy
sudo pip install scrapy
在 Mac OS 10.11 酋长石系统上报错
build/temp.macosx-10.10-x86_64-2.7/_openssl.c:400:10: fatal error: 'openssl/aes.h' file not found
开始以为是 openssl 没有安装,于是尝试
$ brew install openssl
Warning: openssl-1.0.1j already installed
实际上不是,而是因为 Mac OS X 10.11 EL Capital 抛弃了 openssl 的头文件。参考 mac osx 10.11 编译 git 2.6.1 报错
解决方法是, 执行
xcode-select -p
打印 Xcode 的工作目录, 我的是 /Applications/Xcode.app/Contents/Developer, 进入该目录
$ cd /Applications/Xcode.app/Contents/Developer
$ find . -name ssl.h
./Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-migrator/sdk/MacOSX.sdk/usr/include/openssl/ssl.h
找到 openssl 所在的目录
cd Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-migrator/sdk/MacOSX.sdk/usr/include/
cp -R openssl /usr/local/include/
为何要拷贝到 /usr/local/include/ 呢?因为错误日志里,提到 clang 用到了 -I/usr/local/include/
实际上,上面 scrapy 的安装并没有完成,如何运行报错的话,执行下面的操作。如果没有,则略过
ImportError: Twisted requires zope.interface 3.6.0 or later: no module named zope.interface.
sudo pip install zope.interface
ImportError: No module named cryptography.hazmat.bindings.openssl.binding
sudo pip install pyOpenSSL==0.13
另外,Ubuntu 上也不省心 14.04 上会报错
fatal error: libxml/xmlversion.h: No such file or directory
解决方法
sudo pip uninstall scrapy
sudo apt-get install libxml2-dev libxslt1-dev python-dev
如果是 VPS 上,还会遇到内存不够的问题
command 'x86_64-linux-gnu-gcc' failed with exit status 4
问题定位方法参考 dmesg | tail
解决方法参考 设置交换分区
Hello world! 爬取单个页面,热热身
例如爬取 reddit quote 里的名言
# -*- coding: utf-8 -*-
import scrapy
class RedditQuoteSpider(scrapy.Spider):
name = 'reddit-quote'
start_urls = ['https://www.reddit.com/r/quotes/']
def parse(self, response):
for text in response.css('a.title::text'):
print text.extract()
很简单,对不对。相比 BeautifulSoup + Requests 的组合,代码更简洁一些,省去了一些重复代码。 再配上我手撸的 vim snippets 开发效率更是可怕。
Scrapy shell - 调试神器
Scrapy shell 是基于 iPython 的,所以提前把 iPython 装好。
之前经常遇到的问题是,调试爬虫 selector (目标定位),修改一次就要重新运行一次,每运行一次都要重新爬取一次原网页,极其浪费时间。 Scrapy shell 解决了这个问题,例如,我想调试 sunzhongwei.com 页面的爬取, 在 terminal 里执行
scrapy shell "http://www.sunzhongwei.com"
会看到这样的返回
[s] Available Scrapy objects:
[s] crawler <scrapy.crawler.Crawler object at 0x104c6bb10>
[s] item {}
[s] request <GET http://www.sunzhongwei.com>
[s] response <200 http://www.sunzhongwei.com>
[s] settings <scrapy.settings.Settings object at 0x104c6ba90>
[s] spider <DefaultSpider 'default' at 0x10519f950>
[s] Useful shortcuts:
[s] shelp() Shell help (print this help)
[s] fetch(req_or_url) Fetch request (or URL) and update local objects
[s] view(response) View response in a browser
显而易见 response 就是我们经常要用到的调试对象, 即爬取到的网页对象。例如,我想爬取当前网页的 title
In [11]: print response.css("title::text")[0].extract()
大象笔记
这里介绍一下 Scrapy 内置的两种爬取网页内容的 selector, 称为选择器比较好
- css, 类似 jQuery 里的选择器, 我还是适合用这个
- xpath
css, xpath 返回的都是 selector list, 要提取出 unicode list 就需要使用 extract() 或者 re(), 对于只需要获取一条数据时,用 extract_first() 和 re_first() 比使用 extract()[0] 方便多了,至少不需要处理异常。
小技巧,每调试一个页面都需要重新开一个 scrapy shell 么?不需要。 实际上, 还可以这样启动 scrapy shell, 即不带 URL, 在 shell 内更新 URL
scrapy shell
In [4]: fetch("http://www.baidu.com")
比 Scrapy Shell 更方便的调试神器 - Chrome
获取 XPath 的方法
Right click on the node => "Copy XPath"
验证 XPath 的方法
You can use $x in the Chrome javascript console. No extensions needed.
ex: $x("//img")
Also the search box in the web inspector will accept xpath
参考 Is there a way to get the xpath in google chrome?
Chrome 真是个神器的工具!
Scrapy 代码的初始化
实际上 Hello world 那个示例,可以这样自动生成代码
scrapy startproject reddit
cd reddit
scrapy genspider quote reddit.com
cd reddit/reddit/spiders
vim quote.py
记不住命令没问题,scrapy -h 就能看到提示。进入项目执行可以看到更多的命令。
Scrapy 对于写入数据库的操作,如何保证不阻塞网页的爬取
https://segmentfault.com/a/1190000002645467 http://doc.scrapy.org/en/latest/topics/item-pipeline.html
防止被 BAN
设置 USER_AGENTS 之后,从 Nginx 日志中可以明显看到请求的头发生了变化。
112.249.229.127 - - [24/Apr/2016:17:22:53 +0800] "GET / HTTP/1.1" 200 10725 "-" "Scrapy/1.0.3 (+http://scrapy.org)"
112.249.229.127 - - [24/Apr/2016:17:25:50 +0800] "GET / HTTP/1.1" 200 10725 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"
对于请求频率不高的爬虫来说,这就足够了。
微信关注我哦 👍
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式