爬蟲學習之基於 Scrapy 的爬蟲自動登陸

概述

在前面兩篇(爬蟲學習之基於Scrapy的網絡爬蟲爬蟲學習之簡單的網絡爬蟲)文章中咱們經過兩個實際的案例,採用不一樣的方式進行了內容提取。咱們對網絡爬蟲有了一個比較初級的認識,只要發起請求獲取響應的網頁內容,而後對內容進行格式化存儲。不少時候咱們抓取到的內容可能會發生重複,也有多是須要計算或者組織過的全新的內容甚至是須要登陸後才能訪問的內容, 那麼這一篇咱們來學習一下Scrapy的Item部分以及瞭解如何使用Scrapy來進行自動登陸。html

起步

首先咱們使用Scrapy的命令行建立一個新的項目git

scrapy startproject douban

運行後,咱們就有了下面這樣的目錄結構github

+ douban                               # 根目錄
    |- douban                          # Python的項目目錄
        |- spiders                     # 爬蟲Spider部分,用於提取網頁內容
            |- __init__.py
        |- __init__.py
        |- items.py                    # 爬蟲item, 用於定義數據結構
        |- pipelines.py                # 爬蟲pipeline,用於處理提取的結構,好比清洗數據、去重等
        |- settings.py                 # Scrapy框架參數項目參數設置
    |- scrapy.cfg                      # 爬蟲部署相關設置

Scrapy爲咱們生成了已經組織好的目錄結構,上面的註釋部分解釋了每一個文件及目錄的做用。瀏覽器

創建目標

本篇咱們來創建兩個目標,這兩個目標都是基於豆瓣網服務器

  • 目標一:抓取豆瓣TOP250的圖書信息並保存成csv文件cookie

  • 目標二:抓取個人第一頁豆郵標題(須要登陸),並保存成csv文件網絡

分析目標一

目標一是豆瓣的TOP250圖書信息,首先咱們進入到TOP250的列表(https://book.douban.com/top250) ,我用圖示圈出咱們此次要爬取的內容,具體請看圖示:session

豆瓣圖書TOP250

從圖上的框線中咱們主要圈出了書名、價格、出版年份、出版社、評分,其中出版年份,出版社以及價格是在一行中,這個咱們須要進一步處理。數據結構

分頁的處理:總記錄是250條,每頁是25條圖書信息,共分了10頁。app

實現目標一

須要用到的概念:

  • Item

  • Item Pipeline

首先創建Scrapy的Item, Scrapy的Item就是咱們須要存儲的數據結構,先修改items, 而後在spiders目錄中新建一個名爲bookspider.py的Python文件,因爲咱們須要在一堆字符串中提取出出版社和價格等信息因此咱們這裏須要對抓取的內容進一步處理, 在這以前還須要修改settings.py文件:

  1. 加入faker的模擬USER_AGENT數據防止被豆瓣屏蔽,

  2. 也能夠設置DEFAULT_REQUEST_HEADERS參數。

  3. 修改ITEM_PIPELINES

代碼以下所示:

items.py

# -*- coding: utf-8 -*-
'''by sudo rm -rf http://imchenkun.com'''
import scrapy


class DoubanBookItem(scrapy.Item):
    name = scrapy.Field()            # 書名
    price = scrapy.Field()           # 價格
    edition_year = scrapy.Field()    # 出版年份
    publisher = scrapy.Field()       # 出版社
    ratings = scrapy.Field()         # 評分

bookspider.py

# -*- coding:utf-8 -*-
'''by sudo rm -rf http://imchenkun.com'''
import scrapy
from douban.items import DoubanBookItem


class BookSpider(scrapy.Spider):
    name = 'douban-book'
    allowed_domains = ['douban.com']
    start_urls = [
        'https://book.douban.com/top250'
    ]

    def parse(self, response):
        # 請求第一頁
        yield scrapy.Request(response.url, callback=self.parse_next)

        # 請求其它頁
        for page in response.xpath('//div[@class="paginator"]/a'):
            link = page.xpath('@href').extract()[0]
            yield scrapy.Request(link, callback=self.parse_next)

    def parse_next(self, response):
        for item in response.xpath('//tr[@class="item"]'):
            book = DoubanBookItem()
            book['name'] = item.xpath('td[2]/div[1]/a/@title').extract()[0]
            book['price'] = item.xpath('td[2]/p/text()').extract()[0]
            book['ratings'] = item.xpath('td[2]/div[2]/span[2]/text()').extract()[0]
            yield book

pipelines.py

# -*- coding: utf-8 -*-
'''by sudo rm -rf http://imchenkun.com'''


class DoubanBookPipeline(object):
    def process_item(self, item, spider):
        info = item['price'].split(' / ')  # [法] 聖埃克蘇佩裏 / 馬振聘 / 人民文學出版社 / 2003-8 / 22.00元
        item['name'] = item['name']
        item['price'] = info[-1]
        item['edition_year'] = info[-2]
        item['publisher'] = info[-3]
        return item

最後咱們到douban的根目錄中執行如下命令來運行爬蟲來執行並導出數據到csv文件

scrapy crawl douban-book -o douban_book_top250.csv

csv文件截圖以下:

導出的圖書數據

分析目標二

目標二是創建在理解了目標一的基礎上進行的,由於豆瓣登陸次數過多會有驗證碼出現,這裏提供一種手工填寫驗證碼的方式,暫時不討論如何去識別驗證碼,目標二的核心概念是如何提交POST表單和登陸成功後帶Cookie的請求。首先咱們能夠看到頁面結構以下圖所示:

豆瓣郵件列表

實現目標二

定義Item

# -*- coding: utf-8 -*-import scrapy
'''by sudo rm -rf  http://imchenkun.com'''


class DoubanMailItem(scrapy.Item):
    sender_time = scrapy.Field()     # 發送時間
    sender_from = scrapy.Field()     # 發送人
    url = scrapy.Field()             # 豆郵詳細地址
    title = scrapy.Field()           # 豆郵標題

定義doumailspider

# -*- coding:utf-8 -*-
'''by sudo rm -rf  http://imchenkun.com'''
import scrapy
from faker import Factory
from douban.items import DoubanMailItem
import urlparse

f = Factory.create()


class MailSpider(scrapy.Spider):
    name = 'douban-mail'
    allowed_domains = ['accounts.douban.com', 'douban.com']
    start_urls = [
        'https://www.douban.com/'
    ]
    headers = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'Accept-Encoding': 'gzip, deflate, br',
        'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
        'Connection': 'keep-alive',
        'Host': 'accounts.douban.com',
        'User-Agent': f.user_agent()
    }

    formdata = {
        'form_email': '您的帳號',
        'form_password': '您的密碼',
        # 'captcha-solution': '',
        # 'captcha-id': '',
        'login': '登陸',
        'redir': 'https://www.douban.com/',
        'source': 'None'
    }

    def start_requests(self):
        return [scrapy.Request(url='https://www.douban.com/accounts/login',
                               headers=self.headers,
                               meta={'cookiejar': 1},
                               callback=self.parse_login)]

    def parse_login(self, response):
        # 若是有驗證碼要人爲處理
        if 'captcha_image' in response.body:
            print 'Copy the link:'
            link = response.xpath('//img[@class="captcha_image"]/@src').extract()[0]
            print link
            captcha_solution = raw_input('captcha-solution:')
            captcha_id = urlparse.parse_qs(urlparse.urlparse(link).query, True)['id']
            self.formdata['captcha-solution'] = captcha_solution
            self.formdata['captcha-id'] = captcha_id
        return [scrapy.FormRequest.from_response(response,
                                                 formdata=self.formdata,
                                                 headers=self.headers,
                                                 meta={'cookiejar': response.meta['cookiejar']},
                                                 callback=self.after_login
                                                 )]

    def after_login(self, response):
        print response.status
        self.headers['Host'] = "www.douban.com"
        return scrapy.Request(url='https://www.douban.com/doumail/',
                              meta={'cookiejar': response.meta['cookiejar']},
                              headers=self.headers,
                              callback=self.parse_mail)

    def parse_mail(self, response):
        print response.status
        for item in response.xpath('//div[@class="doumail-list"]/ul/li'):
            mail = DoubanMailItem()
            mail['sender_time'] = item.xpath('div[2]/div/span[1]/text()').extract()[0]
            mail['sender_from'] = item.xpath('div[2]/div/span[2]/text()').extract()[0]
            mail['url'] = item.xpath('div[2]/p/a/@href').extract()[0]
            mail['title'] = item.xpath('div[2]/p/a/text()').extract()[0]
            print mail
            yield mail

這裏須要注意的有三個地方:

  1. 第一個是meta中的cookiejar
    Scrapy 經過使用 cookiejar Request meta key來支持單spider追蹤多cookie session。默認狀況下其使用一個cookie jar(session),不過您能夠傳遞一個標示符來使用多個。

  2. start_requests 咱們這裏重寫了爬蟲爬取得第一個頁面,這裏一開始就進去到登陸頁面

  3. 當執行爬蟲的時候,咱們須要把打印出來的驗證碼地址粘貼到瀏覽器中,手動輸入到控制上完成驗證。

同目標一同樣須要設置settings中的相關參數,惟一不一樣的是ITEM_PIPELINES。

最後咱們使用如下命令來啓動爬蟲

scrapy crawl douban-mail -o douban_mail_page1.csv

csv文件截圖以下:

豆郵數據

Github地址:https://github.com/imchenkun/ick-spider/tree/master/douban

總結

本篇咱們學習了若是定義Item以及如何對Item進行進一步處理(Item Pipeline), 還經過登陸豆瓣的案例來了解了若是使用Scrapy進行表單提交和Cookie追蹤,也瞭解了對於有驗證碼的狀況該如何處理,固然咱們這裏暫時還不討論如何識別驗證碼。關於Scrapy的更高級的一些用法和特性能夠進一步閱讀Scrapy官網的文檔。

特別申明:本文所提到的豆瓣網只是拿來進行爬蟲的技術交流學習,讀者涉及到的全部侵權問題都與本人無關,也但願你們在學習實戰的過程當中不要大量的爬取內容對服務器形成負擔

本文首發在sudo rm -rf 採用署名(BY)-非商業性使用(NC)-禁止演繹(ND) 轉載請註明原做者

--EOF--

相關文章
相關標籤/搜索