scrapy

更新日期: 2016-05-14 阅读次数: 13588 分类: 爬虫

对于很多简单页面,厌倦了一行一行自己写爬虫,所以尝试一下 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)"

对于请求频率不高的爬虫来说,这就足够了。

参考 如何让你的scrapy爬虫不再被ban

领取阿里云/腾讯云服务器优惠券

关于作者

我是来自山东烟台的一名开发者,喜欢瞎折腾,顺便记记笔记。有敢兴趣的话题,欢迎加微信 zhongwei 聊聊。 白天写程序,晚上哄熊孩子,可能回复有点慢,见谅。 查看更多联系方式

相关文章

爱评论不评论

近期节日

2020年07月22日 大暑
2020年07月30日 非洲妇女日
2020年08月01日 八一建军节
2020年08月06日 国际电影节
2020年08月07日 立秋
2020年08月15日 日本投降日
2020年08月22日 处暑
2020年08月25日 七夕
2020年09月02日 中元节
2020年09月03日 抗日胜利纪念日
2020年09月07日 白露
2020年09月08日 国际扫盲日
查看更多节日