1. 程式人生 > >三十、scrapy模擬登陸

三十、scrapy模擬登陸

1. 回顧之前的模擬登陸的方法

1.1 requests模組是如何實現模擬登陸的?

- 直接攜帶cookies請求頁面
  • 找url地址,傳送post請求儲存cookie

1.2 selenium是如何模擬登陸的?

  • 找到對應的input標籤,輸入文字點選登陸

1.3 scrapy的模擬登陸

  • 直接攜帶cookies
  • 找url地址,傳送post請求儲存cookie

2. scrapy攜帶cookies直接獲取需要登陸後的頁面

應用場景

  • cookie過期時間很長,常見於一些不規範的網站
  • 能在cookie過期之前把所有的資料拿到
  • 配合其他程式使用,比如其使用selenium把登陸之後的cookie獲取到儲存到本地,scrapy傳送請求之前先讀取本地cookie

2.1 實現:重構scrapy的starte_rquests方法

scrapy中start_url是通過start_requests來進行處理的,其實現程式碼如下

# 這是原始碼
def start_requests(self):
    cls = self.__class__
    if method_is_overridden(cls, Spider, 'make_requests_from_url'):
        warnings.
warn( "Spider.make_requests_from_url method is deprecated; it " "won't be called in future Scrapy releases. Please " "override Spider.start_requests method instead (see %s.%s)." % ( cls.__module__, cls.__name__ ), ) for url in
self.start_urls: yield self.make_requests_from_url(url) else: for url in self.start_urls: yield Request(url, dont_filter=True)

所以對應的,如果start_url地址中的url是需要登入後才能訪問的url地址,則需要重寫start_request方法並在其中手動新增上cookie

2.2 攜帶cookies登陸github

import scrapy
import re

class Login1Spider(scrapy.Spider):
    name = 'login1'
    allowed_domains = ['github.com']
    start_urls = ['https://github.com/NoobPythoner'] # 這是一個需要登陸以後才能訪問的頁面

    def start_requests(self): # 重構start_requests方法
        # 這個cookies_str是抓包獲取的
        cookies_str = '...' # 抓包獲取
        # 將cookies_str轉換為cookies_dict
        cookies_dict = {i.split('=')[0]:i.split('=')[1] for i in cookies_str.split('; ')}
        yield scrapy.Request(
            self.start_urls[0],
            callback=self.parse,
            cookies=cookies_dict
        )

    def parse(self, response): # 通過正則表示式匹配使用者名稱來驗證是否登陸成功
        # 正則匹配的是github的使用者名稱
        result_list = re.findall(r'noobpythoner|NoobPythoner', response.body.decode()) 
        print(result_list)
        pass

注意:

  • scrapy中cookie不能夠放在headers中,在構造請求的時候有專門的cookies引數,能夠接受字典形式的coookie
  • 在setting中設定ROBOTS協議、USER_AGENT

3. scrapy.Request傳送post請求

我們知道可以通過scrapy.Request()指定method、body引數來發送post請求;那麼也可以使用scrapy.FormRequest()來發送post請求

3.1 scrapy.Request()的使用

通過scrapy.Request能夠傳送post請求,同時需要新增body引數作為請求體,以及callback

yield scrapy.Request(
    "https://github.com/session",
    method='POST',
    body={請求體引數post_data},
    # headers={'Content-Type': 'application/json'}
    callback=指定的處理響應的解析函式
)

注意:

  • 抓包發現請求體是payload模式時,需要指定請求體的型別headers={‘Content-Type’: ‘application/json’}

3.2 使用scrapy.FormRequest()登陸github

注意:github的登陸是表單請求,而不是普通的post請求,所以需要使用FormRequests

(1)思路分析

  • 找到post的url地址:點選登入按鈕進行抓包,然後定位url地址為https://github.com/session

  • 找到請求體的規律:分析post請求的請求體,其中包含的引數均在前一次的響應中

    • 否登入成功:通過請求個人主頁,觀察是否包含使用者名稱

(2) 程式碼實現如下:

import scrapy
import re

class Login2Spider(scrapy.Spider):
   name = 'login2'
   allowed_domains = ['github.com']
   start_urls = ['https://github.com/login']

   def parse(self, response):
       authenticity_token = response.xpath("//input[@name='authenticity_token']/@value").extract_first()
       utf8 = response.xpath("//input[@name='utf8']/@value").extract_first()
       commit = response.xpath("//input[@name='commit']/@value").extract_first()

        #構造POST請求,傳遞給引擎
       yield scrapy.FormRequest(
           "https://github.com/session",
           formdata={
               "authenticity_token":authenticity_token,
               "utf8":utf8,
               "commit":commit,
               "login":"noobpythoner",
               "password":"***"
           },
           callback=self.parse_login
       )

   def parse_login(self,response):
       ret = re.findall(r"noobpythoner|NoobPythoner",response.text)
       print(ret)

3.3 小技巧

在settings.py中通過設定COOKIES_DEBUG=TRUE 能夠在終端看到cookie的傳遞傳遞過程