爬蟲實(shí)戰(zhàn)(五)之 Scrapy 驗(yàn)證碼登錄 豆瓣 并爬取用戶信息

隨著反爬的技術(shù)深入,特別是有關(guān)驗(yàn)證碼返回,這對與初學(xué)者來說無疑是遇到了懸崖,原本想開開心心的登錄某個網(wǎng)站并爬取自己需要的信息,可沒想到有些網(wǎng)站當(dāng)你在某一段時間連續(xù)登陸幾次之后他就返回驗(yàn)證碼驗(yàn)證一下是不是人工所為,這對于初學(xué)者來說無疑是撥了一盤冷水,網(wǎng)站之所以這樣做無非就是防止爬蟲爬取他的信息,那么作為爬蟲的開發(fā)者,我們就是使用爬蟲去爬去他的信息,也就是說我們爬蟲者是時時刻刻都在和個站站長斗智斗勇;好了,說了那么多,我們開始進(jìn)入正題吧:今天的任務(wù)就是 登錄豆瓣之后爬取里面的個人發(fā)布過的日記信息-日記標(biāo)題、標(biāo)題鏈接、發(fā)布時間、日記內(nèi)容等
在開始之前,我們先了解下當(dāng)遇到驗(yàn)證碼時,在實(shí)際項(xiàng)目中我們有哪些處理方式,直說了,一般有三種方式:

1) 手動輸入驗(yàn)證碼
2) 通過編寫程序自動識別驗(yàn)證碼-(這里會涉及到人工智能的圖像識別)
3) 通過一些打碼接口實(shí)現(xiàn),比如打碼兔等平臺,讓別人通過接口幫我們輸入驗(yàn)證碼,但是需要支付一定的費(fèi)用

在此,我們將以第一種方式進(jìn)行講解案例的使用,首先,我們來到豆瓣官網(wǎng)的登錄界面:https://accounts.douban.com/login?alias=&redir=https%3A%2F%2Fwww.douban.com%2F&source=index_nav&error=1001,此時不同瀏覽器會有不同的提示,如果有一行提示語點(diǎn)擊“登錄”超鏈接即可來到登錄頁面,然后輸入一個錯誤的賬戶(為了看到深層的登錄鏈接以及登錄參數(shù)),效果圖如下:
18.png
從這個效果圖中顯示沒有驗(yàn)證碼,這很正常,因?yàn)榫W(wǎng)站只有懷疑我們是爬蟲時才返回的,然后我們把隱藏的post請求的連接復(fù)制一份粘貼到網(wǎng)址中訪問,此時可能會出現(xiàn)有驗(yàn)證碼的登錄頁面,然后查看源碼會有以下效果圖:
19.png
接著我們輸入一個正確的用戶名和密碼以及驗(yàn)證碼(注意:此時是需要開發(fā)開發(fā)者模式的),成功登陸之后我們找到 post 請求的鏈接并點(diǎn)擊,如圖:
20.png
我們登陸成功后會自動跳轉(zhuǎn)到主頁,其鏈接為:https://www.douban.com/people/178279892/,效果圖如下:
30.png
因?yàn)槲覀兇龝盒枰D(zhuǎn)到日記頁面中獲取發(fā)布過的日記信息,因此我們必須想辦法獲取上圖中的日記頁面鏈接,經(jīng)過觀察,我們可以通過 xpath 表達(dá)式獲取:
//a[@id="usr-profile-nav-notes"]/@href
先觀察到這里,接下來我們先創(chuàng)建一個爬蟲項(xiàng)目先,使用創(chuàng)建的命令為:scrapy startproject doubanloginproject
然后基于 basic 模板創(chuàng)建一個爬蟲文件,命令為: scrapy genspider -t basic doubanspider douban.com
首先我們打開 items.py 定義我們需要存放數(shù)據(jù)的變量:
import scrapy

class DoubanloginprojectItem(scrapy.Item):
    name = scrapy.Field() #日記標(biāo)題
    href = scrapy.Field() #日記標(biāo)題鏈接
    time = scrapy.Field() #日記發(fā)布時間
    content = scrapy.Field() #日記內(nèi)容

根據(jù)以上效果圖的分析,我們開始編寫我們的爬蟲文件:
# -*- coding: utf-8 -*-
import scrapy
import urllib.request
# from scrapy.http import FormRequest
from doubanloginproject.items import DoubanloginprojectItem

#知乎-會話:https://www.zhihu.com/question/54773510

class DbloginspiderSpider(scrapy.Spider):
    name = 'dbloginspider'
    allowed_domains = ['douban.com']
    start_urls = ['https://accounts.douban.com/login']

    def parse(self, response):
        #首先獲取驗(yàn)證圖片地址并復(fù)制給 imgurl 變量
        imgurl = response.xpath('//img[@id="captcha_image"]/@src').extract()
        #由于驗(yàn)證碼時有時無,因此需要判斷如果有就手動輸入
        if len(imgurl) > 0:
            print("有驗(yàn)證碼返回...")
            #將驗(yàn)證圖片保存到本地中
            local_path = r"C:/Users/Administrator/Desktop/yanzhangma/lcy.png"
            urllib.request.urlretrieve(imgurl[0], filename=local_path)
            #定義接受驗(yàn)證碼變量
            capt_value = input("請查看本地 lcy.png 圖片并輸入對應(yīng)的驗(yàn)證碼-> ")
            #設(shè)置帶有驗(yàn)證碼的 post 信息
            data = {
                "redir":"https://www.douban.com/people/178279892/",#要跳轉(zhuǎn)的鏈接
                "form_email":"12345678@163.com",#用戶名
                "form_password":"luchangyin",#密碼
                "captcha-solution":capt_value,#驗(yàn)證碼
            }

        else:#此時不需要驗(yàn)證碼
            print("無驗(yàn)證碼登錄...")
            #設(shè)置無驗(yàn)證碼請求的參數(shù)
            data = {
                "redir":"https://www.douban.com/people/178279892/",#要跳轉(zhuǎn)的鏈接
                "form_email":"12345678@163.com",#用戶名
                "form_password":"luchangyin",#密碼
            }

        print("登錄中......")
        #帶參的登錄請求
        return [scrapy.FormRequest.from_response(response,
                    #設(shè)置 cookie 信息   注:這兩項(xiàng)在 settings.py 文件中設(shè)置即可
                    #meta={"cookiejar":response.meta["cookiejar"]}, #如果重寫 start_requests()方法,那么該值必須對應(yīng)請求里的 meta 中的鍵
                    #設(shè)置請求頭模擬成瀏覽器
                    #headers=self.headers,
                    #設(shè)置 post 表單中的數(shù)據(jù)
                    formdata=data,
                    #設(shè)置回調(diào)函數(shù)
                    callback=self.mynode,
                    )]



    #之所以創(chuàng)建這個方法是因?yàn)槿绻苯哟蜷_日記鏈接:https://www.douban.com/people/178279892/notes 的話,不需要 cookie 也可以訪問,因此為看到 cookie 的效果我們定義該方法 
    def mynode(self, response):
        #獲取用戶名
        my_name = response.xpath(r'//div[@class="info"]/h1/text()').extract_first()
        #獲取日記頁面的鏈接
        note_url = response.xpath(r'//a[@id="usr-profile-nav-notes"]/@href').extract_first()
        #回調(diào)方法處理的是請求之后的數(shù)據(jù)
        return scrapy.Request(note_url, callback = self.next)



到這里的話,為了驗(yàn)證登錄之后會怎么樣,建議妳在 mynode() 方法中不要就那么快的去請求日記界面鏈接,最好先把響應(yīng)結(jié)果先存到本地的 html 中,然后打開看有木有數(shù)據(jù),在這里我就不做演示了;接下來我們繼續(xù),看看日記頁面需要怎樣獲取相應(yīng)的信息,看圖:
31.png
通過以上方法的請求跳轉(zhuǎn),我們來到了日記數(shù)據(jù)頁面,根據(jù)效果圖的分析結(jié)果,我們再寫個方法獲取日記信息:
    #獲取日記信息方法
    def next(self, response):
        print("......此時已經(jīng)登錄完成并爬去了個人中心的日記數(shù)據(jù)......")
        #獲取日記選項(xiàng)列表
        data_list = response.xpath(r'//div[@class="note-container"]')
        item = DoubanloginprojectItem() #獲取實(shí)體對象
        for data in data_list:
            item["name"] = data.xpath(r'./div[1]/h3/a/text()').extract() #日記標(biāo)題
            item["href"] = data.xpath(r'./div[1]/h3/a/@href').extract() #日記鏈接
            item["time"] = data.xpath(r'./div[1]/div/span/text()').extract()#日記發(fā)布時間
            item["content"] = data.xpath(r'./div[3]/text()').extract() #日記內(nèi)容

            yield item


到目前為止,爬蟲文件搞定了,為了以防萬一,建議在循環(huán)中先輸出下數(shù)據(jù)看看有木有值,這里不做演示;好了,爬蟲文件搞定之后接下來我們就要對這些數(shù)據(jù)進(jìn)行處理,自當(dāng)來到管道文件 pipelines.py :
import csv

class DoubanloginprojectPipeline(object):

    def __init__(self):
        self.f = open("doubannote.csv", "w")
        self.writer = csv.writer(self.f)
        self.writer.writerow(['日記標(biāo)題', '日記鏈接', '日記發(fā)布時間', '日記內(nèi)容'])


    def process_item(self, item, spider):
        #循環(huán)寫入本地文件
        for i in range(0, len(item["name"])):
            #保存為csv文件
            dbnote_list = [item["name"][i], item["href"][i], item["time"][i], item["content"][i]]
            print("管道文件測試-> %s"%dbnote_list)#輸出測試
            self.writer.writerow(dbnote_list)

        return item


    def close_spider(self, spider):
        self.f.close()



最后一步,別忘了在配置文件中啟動管道以及相應(yīng)信息的設(shè)置哦:
# Crawl responsibly by identifying yourself (and your website) on the user-agent
#模擬瀏覽器
USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36'

# Obey robots.txt rules 不遵循網(wǎng)站規(guī)則
ROBOTSTXT_OBEY = False

# Disable cookies (enabled by default)  打開 cookie,當(dāng)然默認(rèn)是打開的
COOKIES_ENABLED = True

#啟動管道文件
ITEM_PIPELINES = {
   'doubanloginproject.pipelines.DoubanloginprojectPipeline': 300,
}


萬事俱備,我們開始破東風(fēng)吧,執(zhí)行爬蟲文件:scrapy crawl dbloginspider --nolog
大致有兩種提示:一種是沒有驗(yàn)證碼,一種是有驗(yàn)證碼:
1)無驗(yàn)證碼
23.png
2)有驗(yàn)證碼
24.png
打開我們本地的 csv 文件:
26.png
圖中可以看到爬取下來的表格中的數(shù)據(jù)后面無意中多了一個空行,只需在管道文件中修改下open()函數(shù)即可:
self.f = open("blogs.csv", "w", newline='')   #newline=''去掉多余的空行
歐了,哈哈哈,也不過如此;如果對您有幫助記得給個贊哦(如有問題可以留言),嘿嘿;下一戰(zhàn):爬取拉勾網(wǎng)信息
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,300評論 25 708
  • 這兩天心口總像是堵著什么東西,難以言語,分外焦慮,難受的想哭,可是最可怕的是你哭都哭不出來…… 馬上就可以...
    by1019閱讀 235評論 0 0
  • 2017-2-16 DAY2:黑廟白廟一日游,晚餐:hot chilli 昨晚1點(diǎn)半睡覺,早上6點(diǎn)起床洗漱收拾,吃...
    liyin1256閱讀 524評論 0 0
  • 【在此閱讀其他章節(jié)】 唐介嵐的第一反應(yīng)就是轉(zhuǎn)身逃跑,然而他剛剛有所動作,威利就立即堵在了他的面前。逃跑無望,他只好...
    坑爹堂閱讀 608評論 1 0
  • 你走的第三十四天,還有79天。我終于熬到了七頭了!想你想你想你,今天下班出來給你找了好多禮物,等你生日的時候一起給...
    rainll閱讀 289評論 0 0

友情鏈接更多精彩內(nèi)容