python 爬虫 scrapy 和 requsts 哪个快_Python爬虫:Scrapy研读之Request/Reponse
本帖最后由 shenzhenwan10 于 2016-6-17 07:52 編輯
1,引言
在前一篇Scrapy:python3下的第一次運(yùn)行測(cè)試 中,我們以官網(wǎng)的tutorial為例,成功的運(yùn)行了Scrapy。
實(shí)際使用中,需要對(duì)Scrapy的各部分有更深入的了解,才能根據(jù)應(yīng)用場(chǎng)景來(lái)靈活的添加自定義代碼。
本篇就來(lái)研讀一下Scrapy有關(guān)Request/Response的部分。
2,研讀過(guò)程
2.1 結(jié)合官方文檔例子,先簡(jiǎn)單整理出一段代碼:
import scrapy
from myproject.items import MyItem
class MySpider(scrapy.Spider):
name = 'myspider'
start_urls = (
'http://example.com/page1',
'http://example.com/page2',
)
def parse(self, response):
# collect `item_urls`
for item_url in item_urls:
yield scrapy.Request(item_url, self.parse_item)
def parse_item(self, response):
item = MyItem()
# populate `item` fields
# and extract item_details_url
yield scrapy.Request(item_details_url, self.parse_details, meta={'item': item})
def parse_details(self, response):
item = response.meta['item']
# populate more `item` fields
return item復(fù)制代碼說(shuō)明:
從Spider繼承了一個(gè)爬蟲(chóng)類,唯一名稱 name="myspider", 爬蟲(chóng)默認(rèn)入口地址 start_urls = () ,元組或列表都可以。
2.2 查看Scrapy有關(guān)Spider的源碼,可以看到
# 代碼片段
class Spider(object_ref):
"""Base class for scrapy spiders. All spiders must inherit from this
class.
"""
name = None
def __init__(self, name=None, **kwargs):
if name is not None:
self.name = name
elif not getattr(self, 'name', None):
raise ValueError("%s must have a name" % type(self).__name__)
self.__dict__.update(kwargs)
if not hasattr(self, 'start_urls'):
self.start_urls = []復(fù)制代碼說(shuō)明:
在Spider初始化時(shí),檢查name是否為None,start_urls 是否存在。代碼很簡(jiǎn)單
2.3 繼續(xù)向下看:
# 第一個(gè)方法
def parse(self, response):
# collect `item_urls`
# 可以理解為:網(wǎng)站的所有導(dǎo)航菜單的超鏈接集合
for item_url in item_urls:
yield scrapy.Request(item_url, self.parse_item)復(fù)制代碼說(shuō)明:
a) parse為默認(rèn)入口,也就是從父類Spider類中繼承過(guò)來(lái)的(或者說(shuō)是一個(gè)必須要實(shí)現(xiàn)的接口),但是需要實(shí)現(xiàn)。
b) 在這個(gè)方法體中,根據(jù) start_requests (默認(rèn)為GET請(qǐng)求)返回的 Response,得到了一個(gè) 名字為‘item_urls’ 的url集合。然后遍歷并請(qǐng)求這些集合。
2.5 再看 Request 源碼:
# 部分代碼
class Request(object_ref):
def __init__(self, url, callback=None, method='GET', headers=None, body=None,
cookies=None, meta=None, encoding='utf-8', priority=0,
dont_filter=False, errback=None):
self._encoding = encoding # this one has to be set first
self.method = str(method).upper()
self._set_url(url)
self._set_body(body)
assert isinstance(priority, int), "Request priority not an integer: %r" % priority
self.priority = priority
assert callback or not errback, "Cannot use errback without a callback"
self.callback = callback
self.errback = errback
self.cookies = cookies or {}
self.headers = Headers(headers or {}, encoding=encoding)
self.dont_filter = dont_filter
self._meta = dict(meta) if meta else None
@property
def meta(self):
if self._meta is None:
self._meta = {}
return self._meta復(fù)制代碼其中,比較常用的參數(shù):
url: 就是需要請(qǐng)求,并進(jìn)行下一步處理的url
callback: 指定該請(qǐng)求返回的Response,由那個(gè)函數(shù)來(lái)處理。
method: 一般不需要指定,使用默認(rèn)GET方法請(qǐng)求即可
headers: 請(qǐng)求時(shí),包含的頭文件。一般不需要。內(nèi)容一般如下:使用 urllib 自己寫過(guò)爬蟲(chóng)的肯定知道
Host: media.readthedocs.org
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0
Accept: text/css,*/*;q=0.1
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://scrapy-chs.readthedocs.org/zh_CN/0.24/
Cookie: _ga=GA1.2.1612165614.1415584110;
Connection: keep-alive
If-Modified-Since: Mon, 25 Aug 2014 21:59:35 GMT
Cache-Control: max-age=0
meta: 比較常用,在不同的請(qǐng)求之間傳遞數(shù)據(jù)使用的。字典dict型
request_with_cookies = Request(url="http://www.example.com",
cookies={'currency': 'USD', 'country': 'UY'},
meta={'dont_merge_cookies': True})
encoding: 使用默認(rèn)的 'utf-8' 就行。
dont_filter: indicates that this request should not be filtered by the scheduler.
This is used when you want to perform an identical request multiple times,
to ignore the duplicates filter. Use it with care, or you will get into crawling loops.
Default to False.
errback: 指定錯(cuò)誤處理函數(shù)
2.6 接下來(lái)就是 Response 的源碼:
# 部分代碼
class Response(object_ref):
def __init__(self, url, status=200, headers=None, body='', flags=None, request=None):
self.headers = Headers(headers or {})
self.status = int(status)
self._set_body(body)
self._set_url(url)
self.request = request
self.flags = [] if flags is None else list(flags)
@property
def meta(self):
try:
return self.request.meta
except AttributeError:
raise AttributeError("Response.meta not available, this response " \
"is not tied to any request")復(fù)制代碼參數(shù)跟上面的類似。
2.7 在繼續(xù)向下看:
# 第二個(gè)方法
def parse_item(self, response):
item = MyItem()
# populate `item` fields
# 相當(dāng)于導(dǎo)航欄下面的列表頁(yè),此時(shí)可能還存在分頁(yè)情況
# and extract item_details_url
yield scrapy.Request(item_details_url, self.parse_details, meta={'item': item})復(fù)制代碼說(shuō)明:
a) 接收到第一個(gè)方法得到并遍歷的所有url的請(qǐng)求響應(yīng)Response。并在當(dāng)前頁(yè)面中查找了所有的詳細(xì)實(shí)體的初略信息,以及單品詳細(xì)的url地址。此時(shí)需要繼續(xù)向下請(qǐng)求,請(qǐng)求詳細(xì)的實(shí)體的頁(yè)面。
b) 在這個(gè)方法中使用到了 item,也可以不使用。直接將信息(比如實(shí)體根據(jù)導(dǎo)航標(biāo)簽的大體分類),通過(guò)Request的meta屬性,傳遞給下一個(gè)callback處理函數(shù)。
2.8 繼續(xù)向下看:
# 第三個(gè)方法
def parse_details(self, response):
item = response.meta['item']
# populate more `item` fields
return item復(fù)制代碼說(shuō)明:此時(shí),請(qǐng)求已經(jīng)得到了實(shí)體的具體頁(yè)面,也就是實(shí)體詳細(xì)頁(yè)。(比如,根據(jù)商品的列表進(jìn)入了詳情)。
這時(shí)需要接收一下,從上一個(gè)方法中傳遞過(guò)來(lái)的信息。
def parse_details(self, response):
item = response.meta['item']
# 也可以使用如下方式,設(shè)置一個(gè)默認(rèn)值
item = response.meta.get('item', None)
# 當(dāng) 'item' key 不存在 meta字典中時(shí),返回None復(fù)制代碼說(shuō)明:
最后將最終得到的 item 返回,這樣就能在 ITEM_PIPELINES 中得到數(shù)據(jù),并進(jìn)行下一步的處理了
3. 下一步
現(xiàn)在網(wǎng)頁(yè)上使用javascript實(shí)在太普遍
a) 研究一下怎樣在Scrapy中加入加載javascript頁(yè)面的代碼
b) 加載和處理javascript頁(yè)面,會(huì)不會(huì)造成阻塞
4,文檔修改歷史
2016-06-17:V1.0,首次發(fā)布
總結(jié)
以上是生活随笔為你收集整理的python 爬虫 scrapy 和 requsts 哪个快_Python爬虫:Scrapy研读之Request/Reponse的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 租房加固话需要去公安局备案吗
- 下一篇: python 双向链表_python算法