1. 程式人生 > >運維學python之爬蟲高級篇(六)scrapy模擬登陸

運維學python之爬蟲高級篇(六)scrapy模擬登陸

markdown inux ins com 是否 準備 配置 獲取圖片 con

上一篇介紹了如何爬取豆瓣TOP250的相關內容,今天我們來模擬登陸GitHub。

1 環境配置

語言:Python 3.6.1 
IDE: Pycharm
瀏覽器:firefox
抓包工具:fiddler
爬蟲框架:Scrapy 1.5.0
操作系統:Windows 10 家庭中文版

2 爬取前分析

分析登陸提交信息
分析登陸信息我使用的是fiddler,fiddler的使用方法就不作介紹了,大家可以自行搜索,首先我們打開github的登陸頁面,輸入用戶名密碼,提交查看fiddler獲取的信息,我這裏第一次故意輸入錯誤的密碼,結果入下:
登陸頁面(https://github.com/login ) :
技術分享圖片
輸入用戶名和錯誤密碼獲取的fiddler結果:

技術分享圖片
這裏我們用火狐開發者工具也可以看到form提交時會加入authenticity_token參數一起,如下圖:
技術分享圖片

3 開始爬蟲

3.1 創建項目

進入你要存儲項目的文件夾中執行下面命令:

scrpy startproject githubspider

可以根據提示繼續創建spider,也可以自己手動創建,使用下面命令:

cd githubspider
scrapy genspider example example.com

如下圖:
技術分享圖片

項目內容如下:
技術分享圖片

3.2 開始前準備

在scrapy.cfg同級目錄下創建pycharm調試腳本run.py,內容如下:

# -*- coding: utf-8 -*-
from scrapy import cmdline

cmdline.execute(‘scrapy crawl github‘.split())

修改settings中的ROBOTSTXT_OBEY = True參數為False,因為默認為True,就是要遵守robots.txt 的規則, robots.txt 是遵循 Robot協議 的一個文件,它保存在網站的服務器中,它的作用是,告訴搜索引擎爬蟲,本網站哪些目錄下的網頁不希望你進行爬取收錄。在Scrapy啟動後,會在第一時間訪問網站的 robots.txt 文件,然後決定該網站的爬取範圍。查看robots.txt可以直接網址後接robots.txt即可如百度:https://www.baidu.com/robots.txt
技術分享圖片
如果我們沒有修改這個參數,則結果如下:
技術分享圖片

3.3 獲取authenticity_token

首先要打開登陸頁面,獲取authenticity_token,代碼如下:

import scrapy
from scrapy.http import Request

class GithubSpider(scrapy.Spider):
    name = ‘github‘
    allowed_domains = [‘github.com‘]

    def start_requests(self):
        urls = [‘https://github.com/login‘]
        for url in urls:
            # 重寫start_requests方法,通過meta傳入特殊key cookiejar,爬取url作為參數傳給回調函數
            yield Request(url, meta={‘cookiejar‘: 1}, callback=self.github_login)

    def github_login(self, response):
        # 首先獲取authenticity_token,這裏可以借助scrapy shell ”url“來獲取頁面
        # 然後從源碼中獲取到authenticity_token的值
        authenticity_token = response.xpath("//input[@name=‘authenticity_token‘]/@value").extract_first()
        # 利用scrapy內置logger打印info信息
        self.logger.info(‘authenticity_token=‘ + authenticity_token)
        pass

結果如下:
技術分享圖片
可以看到我們已經獲取了authenticity_token的值,這一步重點要說明meta、cookiejar和logger。
meta:字典格式的元數據,可以傳遞給下一個函數meta官網解釋;
cookiejar:是meta的一個特殊的key,通過cookiejar參數可以支持多個會話對某網站進行爬取,可以對cookie做標記,1,2,3,4......這樣scrapy就維持了多個會話;
logger:scrapy為每個spider實例內置的日誌記錄器具體信息參考官網logging。

3.4 FormRequest

Scrapy提供了FormRequest類,是Request類的擴展,專門用來進行Form表單提交。我們主要使用FormRequest.from_response()方法來模擬簡單登陸,通過FormRequest.from_response提交後,交給回調函數處理。代碼如下:

     def github_login(self, response):
        # 首先獲取authenticity_token,這裏可以借助scrapy shell ”url“來獲取頁面
        # 然後從源碼中獲取到authenticity_token的值
        authenticity_token = response.xpath("//input[@name=‘authenticity_token‘]/@value").extract_first()
        self.logger.info(‘authenticity_token=‘ + authenticity_token)
        # url可以從fiddler抓取中獲取,dont_click作用是如果是True,表單數據將被提交,而不需要單擊任何元素。
        return FormRequest.from_response(response,
                                         url=‘https://github.com/session‘,
                                         meta={‘cookiejar‘: response.meta[‘cookiejar‘]},
                                         headers=self.headers,
                                         formdata={‘utf8‘: ‘?‘,
                                                   ‘authenticity_token‘: authenticity_token,
                                                   ‘login‘: ‘[email protected]‘,
                                                   ‘password‘: ‘xxxxxx‘},
                                         callback=self.github_after,
                                         dont_click=True,
                                         )

回調函數的代碼如下:

    def github_after(self, response):
        # 獲取登錄頁面主頁中的字符串‘Browse activity‘
        list = response.xpath("//a[@class=‘tabnav-tab selected‘]/text()").extract()
        # 如果含有字符串,則打印日誌說明登錄成功
        if ‘Browse activity‘ in list:
            self.logger.info(‘我已經登錄成功了,這是我獲取的關鍵字:Browse activity‘)

主頁如下:
技術分享圖片

完整的github.py代碼如下:

# -*- coding: utf-8 -*-
import scrapy
from scrapy.http import Request, FormRequest

class GithubSpider(scrapy.Spider):
    name = ‘github‘
    allowed_domains = [‘github.com‘]
    # 頭信息直接從fiddler中復制出來的
    headers = {
        ‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0‘,
        ‘Accept‘: ‘text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8‘,
        ‘Accept-Language‘: ‘zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2‘,
        ‘Accept-Encoding‘: ‘gzip, deflate, br‘,
        ‘Referer‘: ‘https://github.com/‘,
        ‘Content-Type‘: ‘application/x-www-form-urlencoded‘,
    }

    def start_requests(self):
        urls = [‘https://github.com/login‘]
        for url in urls:
            # 重寫start_requests方法,通過meta傳入cookiejar特殊key,爬取url作為參數傳給回調函數
            yield Request(url, meta={‘cookiejar‘: 1}, callback=self.github_login)

    def github_login(self, response):
        # 首先獲取authenticity_token,這裏可以借助scrapy shell ”url“來獲取頁面
        # 然後從源碼中獲取到authenticity_token的值
        authenticity_token = response.xpath("//input[@name=‘authenticity_token‘]/@value").extract_first()
        self.logger.info(‘authenticity_token=‘ + authenticity_token)
        # url可以從fiddler抓取中獲取,dont_click作用是如果是True,表單數據將被提交,而不需要單擊任何元素。
        return FormRequest.from_response(response,
                                         url=‘https://github.com/session‘,
                                         meta={‘cookiejar‘: response.meta[‘cookiejar‘]},
                                         headers=self.headers,
                                         formdata={‘utf8‘: ‘?‘,
                                                   ‘authenticity_token‘: authenticity_token,
                                                   # 這裏是你自己的賬號密碼
                                                   ‘login‘: ‘[email protected]‘,
                                                   ‘password‘: ‘xxxxxx‘},
                                         callback=self.github_after,
                                         dont_click=True,
                                         )

    def github_after(self, response):
        # 獲取登錄頁面主頁中的字符串‘Browse activity‘
        list = response.xpath("//a[@class=‘tabnav-tab selected‘]/text()").extract()
        # 如果含有字符串,則打印日誌說明登錄成功
        if ‘Browse activity‘ in list:
            self.logger.info(‘我已經登錄成功了,這是我獲取的關鍵字:Browse activity‘)
        else:
            self.logger.error(‘登錄失敗‘)

執行後的結果如下:
技術分享圖片

登錄成功了。

4 再來一個列子

不知不覺發現我也寫了好多篇文章了,寫完上面模擬登陸GitHub後,決定趁熱打鐵,模擬登陸51cto,將我寫的博文全部列出來,整理成目錄。
51cto的登陸和GitHub差不多,只不過獲取的是csrf 而不是authenticity_token,用fiddler獲取的結果如下:
技術分享圖片
這裏就不多說了,直接附代碼,51cto.py(spider)內容如下:

# -*- coding: utf-8 -*-
import scrapy
from scrapy.http import FormRequest
from githubspider.items import CtospiderItem

class CtoSpider(scrapy.Spider):
    name = ‘51cto‘
    allowed_domains = [‘51cto.com‘]

    def start_requests(self):
        urls = [‘http://home.51cto.com/index‘]
        for url in urls:
            yield scrapy.Request(url, callback=self.cto_login, meta={‘cookiejar‘: 1})

    def cto_login(self, response):
        # 獲取csrf值
        csrf = response.xpath("//input[@name=‘_csrf‘]/@value").extract_first()
        headers = {
            ‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0‘,
            ‘Accept‘: ‘text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8‘,
            ‘Accept-Language‘: ‘zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2‘,
            ‘Accept-Encoding‘: ‘gzip, deflate, br‘,
            ‘Referer‘: ‘http://blog.51cto.com‘,
            ‘Content-Type‘: ‘application/x-www-form-urlencoded‘,
        }
        # 此處為logger輸出供調試時使用
        # self.logger.info("獲取csrf值為 %s" % csrf)
        yield FormRequest.from_response(response,
                                        url=‘http://blog.51cto.com/linuxliu?type=1‘,
                                        headers=headers,
                                        meta={‘cookiejar‘: response.meta[‘cookiejar‘]},
                                        formdata={
                                                  # 這個位置註意0要加引號,不然會報錯,這個參數意思是是否記住密碼10天內自動登錄
                                                  ‘LoginForm[rememberMe]‘: ‘0‘,
                                                  ‘LoginForm[username]‘: ‘xxxx‘,
                                                  ‘LoginForm[password]‘: ‘xxxx‘,
                                                  ‘_csrf‘: csrf,
                                                  },
                                        callback=self.after_login,
                                        dont_click=True,
                                        )

    def after_login(self, response):
        # 定義item實例,items.py中已經定義好字段
        item = CtospiderItem()
        # 獲取的網頁內容
        resps = response.css("ul.artical-list li")
        for resp in resps:
            # 寫入item字段中
            item[‘title_url‘] = resp.css("a.tit::attr(href)").extract_first()
            item[‘title‘] = resp.css("a.tit::text").extract_first().strip()
            # fullname的格式為“[名稱](鏈接)”之所以這樣是因為
            # markdown語法裏這個表示鏈接的意思,點擊名稱直接打開鏈接內容
            item[‘fullname‘] = ‘[‘ + item[‘title‘] + ‘]‘ + ‘(‘ + item[‘title_url‘] + ‘)‘
            # 此處logger也是調試使用
            # self.logger.info("title url的值為:%s , title的值為%s" % (tit_url, tit))
            yield item

        # 下一頁內容獲取
        next_page = response.css(‘li.next a::attr(href)‘).extract_first()
        # self.logger.info("下一頁鏈接為:%s" % next_page)
        if next_page is not None:
            yield scrapy.Request(next_page, callback=self.after_login)

items.py字段如下:

class CtospiderItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    title = scrapy.Field()
    title_url = scrapy.Field()
    fullname = scrapy.Field()

執行命令寫入csv文件:

scrapy crawl 51cto -o cto.csv

文件結果如下:
技術分享圖片
把我需要的fullname粘到這裏大家就明白了:
運維學python之爬蟲高級篇(五)scrapy爬取豆瓣電影TOP250
運維學python之爬蟲高級篇(四)Item Pipeline介紹(附爬取網站獲取圖片到本地代碼)
運維學python之爬蟲高級篇(三)spider和items介紹
運維學python之爬蟲高級篇(二)用Scrapy框架實現簡單爬蟲
運維學python之爬蟲高級篇(一)Scrapy框架入門
運維學python之爬蟲中級篇(九)Python3 MySQL 數據庫連接
運維學python之爬蟲中級篇(八)MongoDB
運維學python之爬蟲中級篇(七)Sqlite3
運維學python之爬蟲中級篇(六)基礎爬蟲
運維學python之爬蟲中級篇(五)數據存儲(無數據庫版)
運維學python之爬蟲中級篇(四)網絡編程
運維學python之爬蟲中級篇(三)分布式進程
運維學python之爬蟲中級篇(二)線程、協程
運維學python之爬蟲中級篇(一)進程
運維學python之爬蟲工具篇(六)Pyquery的用法
運維學python之爬蟲工具篇(五)Selenium的用法
運維學python之爬蟲工具篇(四)PhantomJS的用法
運維學python之爬蟲工具篇(三)Xpath語法與lxml庫的用法
運維學python之爬蟲工具篇(二)Beautiful Soup的用法
運維學python之爬蟲工具篇(一)Requests庫的用法
運維學python之爬蟲基礎篇實戰(七)爬取伯樂在線面向對象圖片
運維學python之爬蟲基礎篇實戰(六)爬取百度貼吧
運維學python之爬蟲基礎篇(五)正則表達式
運維學python之爬蟲基礎篇(四)Cookie
運維學python之爬蟲基礎篇(三)urllib模塊高級用法
運維學python之爬蟲基礎篇(二)urllib模塊使用
運維學python之爬蟲基礎篇(一)開篇

5 寫在結尾

年前最後一更,過節期間有時間我就更,沒時間可能就不更了,在這裏提前給大家拜個早年,祝大家新春快樂,18年心想事成,另外今天情人節,也祝大家情人節快樂!!!

運維學python之爬蟲高級篇(六)scrapy模擬登陸