python 爬虫 scrapy 和 requsts 哪个快_Python爬虫:Scrapy研读之Request/Reponse
本帖最后由 shenzhenwan10 于 2016-6-17 07:52 編輯
1,引言
在前一篇Scrapy:python3下的第一次運行測試 中,我們以官網的tutorial為例,成功的運行了Scrapy。
實際使用中,需要對Scrapy的各部分有更深入的了解,才能根據應用場景來靈活的添加自定義代碼。
本篇就來研讀一下Scrapy有關Request/Response的部分。
2,研讀過程
2.1 結合官方文檔例子,先簡單整理出一段代碼:
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復制代碼說明:
從Spider繼承了一個爬蟲類,唯一名稱 name="myspider", 爬蟲默認入口地址 start_urls = () ,元組或列表都可以。
2.2 查看Scrapy有關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 = []復制代碼說明:
在Spider初始化時,檢查name是否為None,start_urls 是否存在。代碼很簡單
2.3 繼續向下看:
# 第一個方法
def parse(self, response):
# collect `item_urls`
# 可以理解為:網站的所有導航菜單的超鏈接集合
for item_url in item_urls:
yield scrapy.Request(item_url, self.parse_item)復制代碼說明:
a) parse為默認入口,也就是從父類Spider類中繼承過來的(或者說是一個必須要實現的接口),但是需要實現。
b) 在這個方法體中,根據 start_requests (默認為GET請求)返回的 Response,得到了一個 名字為‘item_urls’ 的url集合。然后遍歷并請求這些集合。
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復制代碼其中,比較常用的參數:
url: 就是需要請求,并進行下一步處理的url
callback: 指定該請求返回的Response,由那個函數來處理。
method: 一般不需要指定,使用默認GET方法請求即可
headers: 請求時,包含的頭文件。一般不需要。內容一般如下:使用 urllib 自己寫過爬蟲的肯定知道
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: 比較常用,在不同的請求之間傳遞數據使用的。字典dict型
request_with_cookies = Request(url="http://www.example.com",
cookies={'currency': 'USD', 'country': 'UY'},
meta={'dont_merge_cookies': True})
encoding: 使用默認的 '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: 指定錯誤處理函數
2.6 接下來就是 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")復制代碼參數跟上面的類似。
2.7 在繼續向下看:
# 第二個方法
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})復制代碼說明:
a) 接收到第一個方法得到并遍歷的所有url的請求響應Response。并在當前頁面中查找了所有的詳細實體的初略信息,以及單品詳細的url地址。此時需要繼續向下請求,請求詳細的實體的頁面。
b) 在這個方法中使用到了 item,也可以不使用。直接將信息(比如實體根據導航標簽的大體分類),通過Request的meta屬性,傳遞給下一個callback處理函數。
2.8 繼續向下看:
# 第三個方法
def parse_details(self, response):
item = response.meta['item']
# populate more `item` fields
return item復制代碼說明:此時,請求已經得到了實體的具體頁面,也就是實體詳細頁。(比如,根據商品的列表進入了詳情)。
這時需要接收一下,從上一個方法中傳遞過來的信息。
def parse_details(self, response):
item = response.meta['item']
# 也可以使用如下方式,設置一個默認值
item = response.meta.get('item', None)
# 當 'item' key 不存在 meta字典中時,返回None復制代碼說明:
最后將最終得到的 item 返回,這樣就能在 ITEM_PIPELINES 中得到數據,并進行下一步的處理了
3. 下一步
現在網頁上使用javascript實在太普遍
a) 研究一下怎樣在Scrapy中加入加載javascript頁面的代碼
b) 加載和處理javascript頁面,會不會造成阻塞
4,文檔修改歷史
2016-06-17:V1.0,首次發布
總結
以上是生活随笔為你收集整理的python 爬虫 scrapy 和 requsts 哪个快_Python爬虫:Scrapy研读之Request/Reponse的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 租房加固话需要去公安局备案吗
- 下一篇: 实木定制地板好不好?使用时间长了会不会裂