国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

Python使用Srapy框架爬蟲模擬登陸并抓取知乎內容

2019-11-25 16:39:50
字體:
來源:轉載
供稿:網友

一、Cookie原理
HTTP是無狀態(tài)的面向連接的協(xié)議, 為了保持連接狀態(tài), 引入了Cookie機制
Cookie是http消息頭中的一種屬性,包括:

  • Cookie名字(Name)Cookie的值(Value)
  • Cookie的過期時間(Expires/Max-Age)
  • Cookie作用路徑(Path)
  • Cookie所在域名(Domain),使用Cookie進行安全連接(Secure)

前兩個參數(shù)是Cookie應用的必要條件,另外,還包括Cookie大小(Size,不同瀏覽器對Cookie個數(shù)及大小限制是有差異的)。

二、模擬登陸
這次主要爬取的網站是知乎
爬取知乎就需要登陸的, 通過之前的python內建庫, 可以很容易的實現(xiàn)表單提交。

現(xiàn)在就來看看如何通過Scrapy實現(xiàn)表單提交。

首先查看登陸時的表單結果, 依然像前面使用的技巧一樣, 故意輸錯密碼, 方面抓到登陸的網頁頭部和表單(我使用的Chrome自帶的開發(fā)者工具中的Network功能)

201672182940777.png (702×170)

查看抓取到的表單可以發(fā)現(xiàn)有四個部分:

  • 郵箱和密碼就是個人登陸的郵箱和密碼
  • rememberme字段表示是否記住賬號
  • 第一個字段是_xsrf,猜測是一種驗證機制
  • 現(xiàn)在只有_xsrf不知道, 猜想這個驗證字段肯定會實現(xiàn)在請求網頁的時候發(fā)送過來, 那么我們查看當前網頁的源碼(鼠標右鍵然后查看網頁源代碼, 或者直接用快捷鍵)

201672183128262.png (1788×782)

發(fā)現(xiàn)我們的猜測是正確的

那么現(xiàn)在就可以來寫表單登陸功能了

def start_requests(self):    return [Request("https://www.zhihu.com/login", callback = self.post_login)] #重寫了爬蟲類的方法, 實現(xiàn)了自定義請求, 運行成功后會調用callback回調函數(shù)  #FormRequeset  def post_login(self, response):    print 'Preparing login'    #下面這句話用于抓取請求網頁后返回網頁中的_xsrf字段的文字, 用于成功提交表單    xsrf = Selector(response).xpath('//input[@name="_xsrf"]/@value').extract()[0]    print xsrf    #FormRequeset.from_response是Scrapy提供的一個函數(shù), 用于post表單    #登陸成功后, 會調用after_login回調函數(shù)    return [FormRequest.from_response(response,                formdata = {              '_xsrf': xsrf,              'email': '123456',              'password': '123456'              },              callback = self.after_login              )]

其中主要的功能都在函數(shù)的注釋中說明
三、Cookie的保存
為了能使用同一個狀態(tài)持續(xù)的爬取網站, 就需要保存cookie, 使用cookie保存狀態(tài), Scrapy提供了cookie處理的中間件, 可以直接拿來使用

CookiesMiddleware:

這個cookie中間件保存追蹤web服務器發(fā)出的cookie, 并將這個cookie在接來下的請求的時候進行發(fā)送
Scrapy官方的文檔中給出了下面的代碼范例 :

for i, url in enumerate(urls):  yield scrapy.Request("http://www.example.com", meta={'cookiejar': i},    callback=self.parse_page)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)

那么可以對我們的爬蟲類中方法進行修改, 使其追蹤cookie

  #重寫了爬蟲類的方法, 實現(xiàn)了自定義請求, 運行成功后會調用callback回調函數(shù)  def start_requests(self):    return [Request("https://www.zhihu.com/login", meta = {'cookiejar' : 1}, callback = self.post_login)] #添加了meta  #FormRequeset出問題了  def post_login(self, response):    print 'Preparing login'    #下面這句話用于抓取請求網頁后返回網頁中的_xsrf字段的文字, 用于成功提交表單    xsrf = Selector(response).xpath('//input[@name="_xsrf"]/@value').extract()[0]    print xsrf    #FormRequeset.from_response是Scrapy提供的一個函數(shù), 用于post表單    #登陸成功后, 會調用after_login回調函數(shù)    return [FormRequest.from_response(response,  #"http://www.zhihu.com/login",              meta = {'cookiejar' : response.meta['cookiejar']}, #注意這里cookie的獲取              headers = self.headers,              formdata = {              '_xsrf': xsrf,              'email': '123456',              'password': '123456'              },              callback = self.after_login,              dont_filter = True              )]

四、偽裝頭部
有時候登陸網站需要進行頭部偽裝, 比如增加防盜鏈的頭部, 還有模擬服務器登陸

201672183151347.png (2136×604)

為了保險, 我們可以在頭部中填充更多的字段, 如下

  headers = {  "Accept": "*/*",  "Accept-Encoding": "gzip,deflate",  "Accept-Language": "en-US,en;q=0.8,zh-TW;q=0.6,zh;q=0.4",  "Connection": "keep-alive",  "Content-Type":" application/x-www-form-urlencoded; charset=UTF-8",  "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36",  "Referer": "http://www.zhihu.com/"  }

在scrapy中Request和FormRequest初始化的時候都有一個headers字段, 可以自定義頭部, 這樣我們可以添加headers字段

形成最終版的登陸函數(shù)

#!/usr/bin/env python# -*- coding:utf-8 -*-from scrapy.contrib.spiders import CrawlSpider, Rulefrom scrapy.selector import Selectorfrom scrapy.contrib.linkextractors.sgml import SgmlLinkExtractorfrom scrapy.http import Request, FormRequestfrom zhihu.items import ZhihuItemclass ZhihuSipder(CrawlSpider) :  name = "zhihu"  allowed_domains = ["www.zhihu.com"]  start_urls = [    "http://www.zhihu.com"  ]  rules = (    Rule(SgmlLinkExtractor(allow = ('/question//d+#.*?', )), callback = 'parse_page', follow = True),    Rule(SgmlLinkExtractor(allow = ('/question//d+', )), callback = 'parse_page', follow = True),  )  headers = {  "Accept": "*/*",  "Accept-Encoding": "gzip,deflate",  "Accept-Language": "en-US,en;q=0.8,zh-TW;q=0.6,zh;q=0.4",  "Connection": "keep-alive",  "Content-Type":" application/x-www-form-urlencoded; charset=UTF-8",  "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36",  "Referer": "http://www.zhihu.com/"  }  #重寫了爬蟲類的方法, 實現(xiàn)了自定義請求, 運行成功后會調用callback回調函數(shù)  def start_requests(self):    return [Request("https://www.zhihu.com/login", meta = {'cookiejar' : 1}, callback = self.post_login)]  #FormRequeset出問題了  def post_login(self, response):    print 'Preparing login'    #下面這句話用于抓取請求網頁后返回網頁中的_xsrf字段的文字, 用于成功提交表單    xsrf = Selector(response).xpath('//input[@name="_xsrf"]/@value').extract()[0]    print xsrf    #FormRequeset.from_response是Scrapy提供的一個函數(shù), 用于post表單    #登陸成功后, 會調用after_login回調函數(shù)    return [FormRequest.from_response(response,  #"http://www.zhihu.com/login",              meta = {'cookiejar' : response.meta['cookiejar']},              headers = self.headers, #注意此處的headers              formdata = {              '_xsrf': xsrf,              'email': '1095511864@qq.com',              'password': '123456'              },              callback = self.after_login,              dont_filter = True              )]  def after_login(self, response) :    for url in self.start_urls :      yield self.make_requests_from_url(url)  def parse_page(self, response):    problem = Selector(response)    item = ZhihuItem()    item['url'] = response.url    item['name'] = problem.xpath('//span[@class="name"]/text()').extract()    print item['name']    item['title'] = problem.xpath('//h2[@class="zm-item-title zm-editable-content"]/text()').extract()    item['description'] = problem.xpath('//div[@class="zm-editable-content"]/text()').extract()    item['answer']= problem.xpath('//div[@class=" zm-editable-content clearfix"]/text()').extract()    return item

五、Item類和抓取間隔
完整的知乎爬蟲代碼鏈接

from scrapy.item import Item, Fieldclass ZhihuItem(Item):  # define the fields for your item here like:  # name = scrapy.Field()  url = Field() #保存抓取問題的url  title = Field() #抓取問題的標題  description = Field() #抓取問題的描述  answer = Field() #抓取問題的答案  name = Field() #個人用戶的名稱

設置抓取間隔, 訪問由于爬蟲的過快抓取, 引發(fā)網站的發(fā)爬蟲機制, 在setting.py中設置

BOT_NAME = 'zhihu'SPIDER_MODULES = ['zhihu.spiders']NEWSPIDER_MODULE = 'zhihu.spiders'DOWNLOAD_DELAY = 0.25  #設置下載間隔為250ms

更多設置可以查看官方文檔

抓取結果(只是截取了其中很少一部分)

... 'url': 'http://www.zhihu.com/question/20688855/answer/16577390'}2014-12-19 23:24:15+0800 [zhihu] DEBUG: Crawled (200) <GET http://www.zhihu.com/question/20688855/answer/15861368> (referer: http://www.zhihu.com/question/20688855/answer/19231794)[]2014-12-19 23:24:15+0800 [zhihu] DEBUG: Scraped from <200 http://www.zhihu.com/question/20688855/answer/15861368>  {'answer': [u'/u9009/u4f1a/u8ba1/u8fd9/u4e2a/u4e13/u4e1a/uff0c/u8003CPA/uff0c/u5165/u8d22/u52a1/u8fd9/u4e2a/u884c/u5f53/u3002/u8fd9/u4e00/u8def/u8d70/u4e0b/u6765/uff0c/u6211/u53ef/u4ee5/u5f88/u80af/u5b9a/u7684/u544a/u8bc9/u4f60/uff0c/u6211/u662f/u771f/u7684/u559c/u6b22/u8d22/u52a1/uff0c/u70ed/u7231/u8fd9/u4e2a/u884c/u4e1a/uff0c/u56e0/u6b64/u575a/u5b9a/u4e0d/u79fb/u5730/u5728/u8fd9/u4e2a/u884c/u4e1a/u4e2d/u8d70/u4e0b/u53bb/u3002',        u'/u4e0d/u8fc7/u4f60/u8bf4/u6709/u4eba/u4ece/u5c0f/u5c31/u559c/u6b22/u8d22/u52a1/u5417/uff1f/u6211/u89c9/u5f97/u51e0/u4e4e/u6ca1/u6709/u5427/u3002/u8d22/u52a1/u7684/u9b45/u529b/u5728/u4e8e/u4f60/u771f/u6b63/u61c2/u5f97/u5b83/u4e4b/u540e/u3002',        u'/u901a/u8fc7/u5b83/uff0c/u4f60/u53ef/u4ee5/u5b66/u4e60/u4efb/u4f55/u4e00/u79cd/u5546/u4e1a/u7684/u7ecf/u8425/u8fc7/u7a0b/uff0c/u4e86/u89e3/u5176/u7eb7/u7e41/u5916/u8868/u4e0b/u7684/u5b9e/u7269/u6d41/u3001/u73b0/u91d1/u6d41/uff0c/u751a/u81f3/u4f60/u53ef/u4ee5/u638c/u63e1/u5982/u4f55/u53bb/u7ecf/u8425/u8fd9/u79cd/u5546/u4e1a/u3002',        u'/u5982/u679c/u5bf9/u4f1a/u8ba1/u7684/u8ba4/u8bc6/u4ec5/u4ec5/u505c/u7559/u5728/u505a/u5206/u5f55/u8fd9/u4e2a/u5c42/u9762/uff0c/u5f53/u7136/u4f1a/u89c9/u5f97/u67af/u71e5/u65e0/u5473/u3002/u5f53/u4f60/u5bf9/u5b83/u7684/u8ba4/u8bc6/u8fdb/u5165/u5230/u6df1/u5c42/u6b21/u7684/u65f6/u5019/uff0c/u4f60/u81ea/u7136/u5c31/u4f1a/u559c/u6b22/u4e0a/u5b83/u4e86/u3002/n/n/n'],   'description': [u'/u672c/u4eba/u5b66/u4f1a/u8ba1/u6559/u80b2/u4e13/u4e1a/uff0c/u6df1/u611f/u5176/u67af/u71e5/u4e4f/u5473/u3002/n/u5f53/u521d/u662f/u51b2/u7740/u5e08/u8303/u4e13/u4e1a/u62a5/u7684/uff0c/u56e0/u4e3a/u68a6/u60f3/u662f/u6210/u4e3a/u4e00/u540d/u8001/u5e08/uff0c/u4f46/u662f/u611f/u89c9/u73b0/u5728/u666e/u901a/u521d/u9ad8/u4e2d/u8001/u5e08/u5df2/u7ecf/u8d8b/u4e8e/u9971/u548c/uff0c/u800c/u987a/u6bcd/u4eb2/u5927/u4eba/u7684/u610f/u9009/u4e86/u8fd9/u4e2a/u4e13/u4e1a/u3002/u6211/u559c/u6b22/u4e0a/u6559/u80b2/u5b66/u7684/u8bfe/uff0c/u5e76/u597d/u7814/u7a76/u5404/u79cd/u6559/u80b2/u5fc3/u7406/u5b66/u3002/u4f46/u4f1a/u8ba1/u8bfe/u4f3c/u4e4e/u662f/u4e3b/u6d41/u3001/u54ce/u3002/n/n/u4e00/u76f4/u4e0d/u559c/u6b22/u94b1/u4e0d/u94b1/u7684/u4e13/u4e1a/uff0c/u6240/u4ee5/u5f88/u597d/u5947/u5927/u5bb6/u9009/u4f1a/u8ba1/u4e13/u4e1a/u5230/u5e95/u662f/u51fa/u4e8e/u4ec0/u4e48/u76ee/u7684/u3002/n/n/u6bd4/u5982/u8bf4/u5b66/u4e2d/u6587/u7684/u4f1a/u8bf4/u4ece/u5c0f/u559c/u6b22/u770b/u4e66/uff0c/u4f1a/u6709/u4ece/u5c0f/u559c/u6b22/u4f1a/u8ba1/u501f/u554a/u8d37/u554a/u7684/u7684/u4eba/u5417/uff1f'],   'name': [],   'title': [u'/n/n', u'/n/n'],   'url': 'http://www.zhihu.com/question/20688855/answer/15861368'}...

六、存在問題

  • Rule設計不能實現(xiàn)全網站抓取, 只是設置了簡單的問題的抓取
  • Xpath設置不嚴謹, 需要重新思考
  • Unicode編碼應該轉換成UTF-8

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 罗山县| 永修县| 天长市| 攀枝花市| 中阳县| 永泰县| 徐汇区| 平和县| 遵义市| 麟游县| 望谟县| 江永县| 洪江市| 滦南县| 正蓝旗| 临洮县| 乐清市| 右玉县| 介休市| 宿州市| 松滋市| 瓦房店市| 和硕县| 江阴市| 乌拉特中旗| 革吉县| 汤原县| 韶山市| 丘北县| 囊谦县| 中牟县| 阳新县| 平度市| 舒兰市| 德昌县| 金坛市| 定边县| 禄丰县| 汉源县| 江油市| 自治县|