本章將介紹Request與Response,更多內(nèi)容請參考:Python學(xué)習(xí)指南
Request
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
其中惕味,比較常用的參數(shù):
url:就是需要請求,并進行下一步處理的url
callback:指定該請求返回的response彭谁,由哪個函數(shù)來處理瓷患。
method: 請求一般不需要指定铃肯,默認為GET方法己沛,可設(shè)置為"GET"、"POST"商乎、"PUT"等央拖,且保證字符串大寫。
headers: 請求時鹉戚,包含的頭文件鲜戒。一般不需要,內(nèi)容一般如下:
- Host:media.readthedocs.org
- User-Agent:Mozilla/5.0 (Window NT 6.2; WOW64; rv:33.0) Cecko/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
- Referrer:http://scrapy-chs.readthedocs.org/zh_CN/0.24
- Cookie:_ga=GA2.1612165614.14532342342
- Connection:keep-alive
- If-Modified-Since:Mon, 25 Aug 2015 21:59:35 GMT
- Cache-Contro:max-age=0
meta:比較常用崩瓤,在不同的請求之間傳遞數(shù)據(jù)使用的。字典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:表明該請求不由調(diào)度器過濾却桶。這是當(dāng)你想使用多次執(zhí)行相同的其你去,就忽略重復(fù)的過濾器。默認為False
errback:指定錯誤處理函數(shù)
Request.meta
Request.meata
在不同請求之間傳遞數(shù)據(jù)使用的颖系。
Request.meta
屬性可以包含任意的數(shù)據(jù)嗅剖,但是Scrapy
和它的內(nèi)置擴展可以識別一些特殊的鍵。
- dont_rediect:不重定向
- dont_retry:不重試
- handle_httpstatus_list
- dont_merge_cookies:不合并cookie
- cookiejar:使用cookiejar
- rediect_urls:重定向連接
- bindaddress:綁定ip地址
- dont_obey_robotstxt:不遵循反爬蟲協(xié)議
- download_timeout:下載超時
Request的子類FormRequest
FormRequest是Request的子類嘁扼,一般用作表單數(shù)據(jù)提交信粮。
class FormRequest(Request):
def __init__(self, *args, **kwargs):
formdata = kwargs.pop('formdata', None)
if formdata and kwargs.get('method') is None:
kwargs['method'] = 'POST'
super(FormRequest, self).__init__(*args, **kwargs)
FormRequest的構(gòu)造:
class scrapy.http.FormRequest(url, [formdata,...])
FormRequest類除了有Request的功能,還提供了form_response
的功能
def from_response(cls, response, formname=None, formid=None, formnumber=0, formdata=None,clickdata=None, dont_click=False, formxpath=None, formcss=None, **kwargs)
-
response
:是指包含HTML表單的Response對象趁啸,該表單將用于預(yù)填充表單字段强缘。 -
formname
:如果給定,將使用form表單的name屬性為該值的name屬性的表單不傅。 -
formid
:如果給定旅掂,將使用form表單的id屬性為該值的name屬性的表單 -
formnumber
:當(dāng)響應(yīng)包含多個表單時,要使用的表單的數(shù)量访娶。 formnumber默認是0商虐,表示使用第一個。 -
formdata
:字段來覆蓋表單數(shù)據(jù)崖疤。如果一個字段已經(jīng)存在于響應(yīng)<form>元素中秘车,那么它的值被在這個參數(shù)中傳遞的值覆蓋。 -
formxpath
:如果給定劫哼,將使用與XPath匹配的第一個表單叮趴。 -
clickdata
:查找單擊控件的屬性。如果沒有給出沦偎,表單數(shù)據(jù)將被提交模擬點擊第一個可點擊的元素疫向。 -
dont_click
:如果為True,表單數(shù)據(jù)將被提交而不需要單擊任何元素豪嚎。
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")
大部分參數(shù)和上面的差不多:
status :響應(yīng)的狀態(tài)碼
body :響應(yīng)體
url :響應(yīng)url
headers:響應(yīng)對象的響應(yīng)報頭
meta:為response.meta屬性的初始值搔驼。如果給定的,字典將淺復(fù)制侈询。
Response的子類
Response的繼承關(guān)系
Response
TextResponse
HtmlResponse
XmlResponse
TextResponse
class scrapy.http.TextResponse(url[,encoding[,...]])
TextResponse
對象增加了編碼能力的基礎(chǔ)響應(yīng)類舌涨,是指將只用于二進制數(shù)據(jù),如圖像扔字、生硬或任何媒體文件囊嘉。
TextResponse
對象除了標準的Response對象外,還支持以下屬性和方法:
-
encoding
:
與此響應(yīng)編碼的字符串革为。 通過嘗試以下機制來解決編碼問題:- 在構(gòu)造函數(shù)編碼參數(shù)中傳遞的編碼
- 在Content-Type HTTP頭中聲明的編碼扭粱。如果這種編碼是無效的(即未知的),它將被忽略震檩,并嘗試下一個解析機制琢蛤。
- 在響應(yīng)正文中聲明的編碼蜓堕。TextResponse類不提供任何特殊的功能。但是博其,HtmlResponse和XmlResponse類可以套才。
- 通過查看響應(yīng)主體來推斷編碼。 這是更脆弱的方法慕淡,但也是最后一個嘗試背伴。
selector
: 使用響應(yīng)作為目標的選擇器實例。``body_as_unicode()` : 以unicode形式返回響應(yīng)的主體峰髓。
xpath(query)
: xpath解析
textresponse.selector.css('p')
#也可以簡寫為:
textresponse.css('p')
-
css(query)
: :css解析傻寂,相當(dāng)于BeautifulSoup4解析
textresponse.selector.css('p')
#也可以簡寫為:
textresponse.css('p')
HtmlResponse
HtmlResponse
類是TextResponse
的一個子類,它通過查看HTML meta http-equiv屬性來添加編碼自動發(fā)現(xiàn)支持儿普。
XmlResponse
XmlResponse
類是TextResponse
的一個子類崎逃,它通過查看XML聲明行來添加編碼自動發(fā)現(xiàn)支持。
Response的
發(fā)送POST請求
- 可以使用
yield scrapy.FormRequest(url, formdata, callback)
的方法發(fā)送POST請求眉孩。 - 如果希望程序執(zhí)行一開始就發(fā)送POST請求个绍,可以重寫Spider類的start_requests(self)方法,并且不再調(diào)用start_urls里的url浪汪。
class mySpider(scrapy.Spider):
#start_utls = ['http://www.example d']
def start_requests(self):
url = "http://www.renren.com/PLogin.do"
#FormRequest是Scrapy發(fā)送POST請求的方法
yield scrapy.FormRequest(
url = url,
formdata = {"email" : "xxxx@qq.com", "password":"xxxxxx"}
callback = self.parse_page
)
def parse_page(self, response):
#do something
模擬登陸
使用FormRequest.form_response()方法模擬用戶登陸
通常網(wǎng)站通過實現(xiàn)對某些表單字段(如數(shù)據(jù)或者登陸界面中的認證令牌等)的預(yù)填充巴柿。
使用Scrapy抓取網(wǎng)頁時,如果想要預(yù)填充或重寫像用戶名死遭、用戶密碼這些表單字段時广恢,可以使用FormRequest.from_response()方法實現(xiàn)。
在Request中不存在formadata參數(shù)呀潭,所以無法使用提交表單的方式
下面是使用這種方法的爬蟲例子:
import scrapy
class LoginSpider(scrapy.Spider):
name = 'example.com'
start_urls = ['http://www.example.com/users/login.php']
def parse(self, response):
return scrapy.FormRequest.from_response(
response,
formdata={'username': 'john', 'password': 'secret'},
callback=self.after_login
)
def after_login(self, response):
# check login succeed before going on
if "authentication failed" in response.body:
self.log("Login failed", level=log.ERROR)
return
# continue scraping with authenticated session...
Github爬蟲案例參考:
#-*- coding:utf-8 -*-
from scrapy import Spider, Request, FormRequest
class GithubLoginSpider(Spider):
name = "github"
allow_domains = ['github.com']
#post登入必須的頭字段
post_headers = {
"User-Agent" : "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36",
"Referer" : "https://github.com",
"Origin" : 'https://github.com',
"Host":'github.com'
}
def start_requests(self):
"""
執(zhí)行spider請求
:return 返回一個Request對象钉迷,請求登陸的頁面
"""
return [Request(url="https://github.com/login", meta={"cookiejar":1}, callback = self.post_login, headers = self.post_headers)]
def post_login(self, response):
"""
登陸的頁面請求成功后,解析響應(yīng)的頁面钠署,獲取登陸需要的<input>標簽信息
:param response :登陸接口返回的頁面
"""
#github登陸上傳必要的字段
utf8 = response.xpath('//form//input[@name="utf8"]/@value').extract()[0]
authenticity_token = response.xpath('//form//input[@name="authenticity_token"]/@value').extract()[0]
login = "xxxx@qq.com"
password = "xxxxxx"
commit = response.xpath('//form//input[@name="commit"]/@value').extract()[0]
#發(fā)送FormRequest表單請求
return FormRequest.from_response(response=response, meta={"cookiejar":response.meta['cookiejar']},
formdata = {
"utf8" : utf8,
"authenticity_token" :authenticity_token,
"login" : login,
"password" : password,
"commit" : commit
},
callback = self.after_login,
headers = self.post_headers
)
def after_login(self, response):
"""
form表單請求成功后糠聪,請求登陸我的頁面
:param response
:return:返回一個響應(yīng)
"""
print(response.body)
if response.status == 200:
with open("my_github.html", "wb") as f:
f.write(response.body)
禁用遵循robot協(xié)議,打開Cookie
ROBOTSTXT_OBEY = False
COOKIE_ENABLED = True
啟動爬蟲
scrapy crawl github