Zhangxu's Blog.

Scrapy实用技巧

Word count: 1,149 / Reading time: 6 min
2017/12/28 Share

在使用scrapy过程中总结了一些小技巧,在此分享出来供大家参考。

用 LinkExtractor 收取链接

http://www.hao123.com/sitemap 为例子:

在shell中运行

1
scrapy shell http://www.hao123.com/sitemap

进入shell调试模式,我们来看看使用linkextractors的效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> from scrapy.linkextractors import LinkExtractor
>>> links = LinkExtractor(allow=(), restrict_xpaths=('//a[@class="link"]')).extract_links(response)
>>> len(links)
113
>>> for link in links[:10]:
... print(link.text.replace('\n',''),':',link.url)
...
天气 : http://tianqi.hao123.com/
万年历 : http://www.hao123.com/rili
地图 : http://www.hao123.com/map
查询 : http://life.hao123.com/info
生活 : http://www.hao123.com/shenghuo
hao到家 : http://life.hao123.com/
美食菜谱 : http://www.hao123.com/menu
特价 : http://tejia.hao123.com/?tn=kztj
购物 : http://gouwu.hao123.com/
团购 : https://www.nuomi.com/?utm_source=hao123&utm_medium=channel_midright&cid=001606

利用Xpath,可以很方便的获取到链接的文本和URL

命令行调试代码

1
2
from scrapy.shell import inspect_response
inspect_response(response, self)

在需要调试的地方插入此代码,程序运行过程中会停在该处,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
2018-05-28 10:29:14 [scrapy.core.engine] INFO: Spider opened
2018-05-28 10:29:14 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
[s] Available Scrapy objects:
>>> [s] scrapy scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s] crawler <scrapy.crawler.Crawler object at 0x10549dfd0>
[s] item {}
[s] request <GET https://movie.douban.com/chart>
[s] response <200 https://movie.douban.com/chart>
[s] settings <scrapy.settings.Settings object at 0x10549def0>
[s] spider <TestSpider 'test' at 0x1055e1748>
[s] Useful shortcuts:
[s] shelp() Shell help (print this help)
[s] view(response) View response in a browser
>>>

此时可以针对返回的response进行调试工作。

重写 start_requests 方法

我们知道在编写spider的时候都有一个初始URL列表,也即start_urls,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import scrapy
class StackOverflowSpider(scrapy.Spider):
name = 'stackoverflow'
start_urls = ['http://stackoverflow.com/questions?sort=votes']

def parse(self, response):
for href in response.css('.question-summary h3 a::attr(href)'):
full_url = response.urljoin(href.extract())
yield scrapy.Request(full_url, callback=self.parse_question)

def parse_question(self, response):
yield {
'title': response.css('h1 a::text').extract()[0],
'votes': response.css('.question .vote-count-post::text').extract()[0],
'body': response.css('.question .post-text').extract()[0],
'tags': response.css('.question .post-tag::text').extract(),
'link': response.url,
}

但有时我们希望灵活的把初始URL分配给不同的回调函数,这时我们可以重写Spider类的start_requests 方法:

1
2
3
4
5
6
def start_requests(self):
ershoufang = "https://nj.5i5j.com/ershoufang/o6/"
zufang = "https://nj.5i5j.com/zufang/o6/"

yield Request(ershoufang, callback=self.parse_ershoufang,dont_filter = True)
yield Request(zufang, callback=self.parse_zufang,dont_filter = True)

当然你还可以基于这个方法做一个URL和parse的映射,这样就可以在一个爬虫下处理不同类型的页面。

Request.meta 特殊键

Request.meta属性可以包含任何任意数据,也就意味着除了Scrapy及其内置扩展的一些特殊键,我们可以自定义一些对我们有用的键用于在请求和响应间传递,拿官方示例的 cookiejar 来说。

Scrapy通过使用 cookiejar Request meta key来支持单spider追踪多cookie session。 默认情况下其使用一个cookie jar(session),不过您可以传递一个标示符来使用多个。

例如:

1
2
3
for i, url in enumerate(urls):
yield scrapy.Request("http://www.example.com", meta={'cookiejar': i},
callback=self.parse_page)

需要注意的是 cookiejar meta key不是”黏性的(sticky)”。 您需要在之后的request请求中接着传递。例如:

1
2
3
4
5
def parse_page(self, response):
# do some processing
return scrapy.Request("http://www.example.com/otherpage",
meta={'cookiejar': response.meta['cookiejar']},
callback=self.parse_other_page)

具体如何使用,就看你的想象力啦。

给请求添加代理(中间件)

爬虫不可避免的需要使用代理,我们通过下载器中间件,截获发出的请求把代理信息添加进去。

以阿布云为例,首先我们需要编辑项目下的middlewares.py文件,新建一个代理中间件类:

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

# 代理服务器
proxyServer = "http://http-dyn.abuyun.com:9020"

# 代理隧道验证信息
proxyUser = "H01234567890123D"
proxyPass = "0123456789012345"

# for Python2
# proxyAuth = "Basic " + base64.b64encode(proxyUser + ":" + proxyPass)

# for Python3
proxyAuth = "Basic " + base64.urlsafe_b64encode(bytes((proxyUser + ":" + proxyPass), "ascii")).decode("utf-8")

class ProxyMiddleware(object):
def process_request(self, request, spider):
request.meta["proxy"] = proxyServer

request.headers["Proxy-Authorization"] = proxyAuth

在重写的process_request方法中,我们将必要的信息添加给即将发出的request。

然后我们还需要在 settings.py 文件中使能我们自定义的代理中间件:

1
2
3
4
5
# Enable or disable downloader middlewares
# See http://scrapy.readthedocs.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = {
'myproject.middlewares.ProxyMiddleware': 543,
}

这样我们发出的请求scrapy就会自动为我们添加代理信息了。

Scrapy 动态调试和启动多爬虫

参见我之前的一篇文章

… …

CATALOG
  1. 1. 用 LinkExtractor 收取链接
  2. 2. 命令行调试代码
  3. 3. 重写 start_requests 方法
  4. 4. Request.meta 特殊键
  5. 5. 给请求添加代理(中间件)
  6. 6. Scrapy 动态调试和启动多爬虫
  7. 7. … …