【爬蟲實戰(zhàn)】利用scrapy框架爬取豆瓣圖書信息

?本文作者:陳 鼎 中南財經(jīng)政法大學(xué)統(tǒng)計與數(shù)學(xué)學(xué)院

文字編輯:任 哲

技術(shù)總編:張馨月

一、前言

??scrapy是基于twisted的異步處理框架瑟幕,與傳統(tǒng)的requests爬蟲程序執(zhí)行流程不同合冀,scrapy使用多線程窟却,將發(fā)送請求刽酱,提取數(shù)據(jù)臭蚁,保存數(shù)據(jù)等操作分別交給Scheduler(調(diào)度器)载城,Downloader(下載器)肌似,Spider(爬蟲),Pipeline(管道)等爬蟲“組件”來完成诉瓦。多線程的運行框架使得爬蟲的效率大大提升川队,讓爬蟲程序變得更快,更強睬澡」潭睿基于以上特點,本文將以爬取豆瓣圖書信息為例煞聪,簡要闡述基于scrapy框架下的爬蟲實現(xiàn)流程斗躏。

二、爬蟲流程以及代碼實現(xiàn)

(一)分析需要爬取的網(wǎng)頁結(jié)構(gòu)

??在編寫一個爬蟲項目之前昔脯,我們需要對所需爬取的網(wǎng)頁有一個清晰的認識啄糙。爬蟲的本質(zhì)是在響應(yīng)中的字符串提取所需信息,即只有我們提取到的響應(yīng)中存在我們所需要的數(shù)據(jù)時云稚,我們才能進行爬蟲隧饼。我們訪問豆瓣讀書(https://book.douban.com/tag/?view=type),發(fā)現(xiàn)豆瓣圖書標簽中存在許多大分類(文學(xué)静陈,文化...)燕雁,大分類中存在許多小分類(小說,外國文學(xué)...)鲸拥。點開每個小分類標簽拐格,會呈現(xiàn)出不同類型的書的列表清單,且不止一頁刑赶。我們要做的就是提取豆瓣所有類型書籍下的所有書籍的簡要信息禁荒,包括圖書作者,書名角撞,圖書價格呛伴,豆瓣評分勃痴,書籍評論人數(shù)等。網(wǎng)頁的頁面如下圖所示:

image

圖1.豆瓣的圖書標簽頁

image

圖2.豆瓣每個小標簽下的url頁面

(二)創(chuàng)建scrapy項目

??創(chuàng)建scrapy項目十分簡單热康,首先打開命令提示符耐版,通過cd命令路徑抬闯,將工作路徑定位到我們需要創(chuàng)建項目的路徑下,然后創(chuàng)建一個scrapy項目,用到的程序如下:

scrapy startproject douban_books #創(chuàng)建一個名字為douban_books的爬蟲項目
cd douban_books #定位到項目文件夾內(nèi)
scrapy genspider book book.douban.com #創(chuàng)建爬蟲所需的腳本文件book.py细睡;book.douban.com設(shè)置允許爬取的網(wǎng)頁范圍(allow_domains)                                                                     
image

圖3.scrapy項目內(nèi)容顯示

(三)設(shè)置USER_AGENT颈将,LOG_LEVEL

??接下里我們切換到settings.py文件中挤茄,對爬蟲項目進行變量配置與賦值逞刷。首先,利用url地址請求頭中的USER_AGENT對發(fā)送請求進行偽裝惊暴,可更加順利地發(fā)送請求并獲取到服務(wù)器的響應(yīng)饼丘。用LOG_LEVEL設(shè)置的日志級別,讓打印出來的結(jié)果更加干凈辽话,整潔肄鸽。

USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36' #設(shè)置useragent
LOG_LEVEL = 'WARNING' #設(shè)置日志級別,即輸出結(jié)果只會顯示warning以及warning以上的日志

(四)編寫爬蟲程序

??打開spiders文件夾下的book.py文件油啤,我們將在此文件中編寫實現(xiàn)提取數(shù)據(jù)的核心代碼典徘。

??在此程序中,start_url為我們首先要發(fā)送的url地址益咬,該url地址不受allowed_domains約束逮诲;parse函數(shù)用來執(zhí)行提取start_url頁面數(shù)據(jù)的主要邏輯,需要注意幽告,該函數(shù)名不可以隨意更改梅鹦。如下:

import scrapy
import re
from copy import deepcopy

class BookSpider(scrapy.Spider):
    name = 'book'#爬蟲名
    allowed_domains = ['book.douban.com'] #允許爬取的url地址范圍
    start_urls = ['https://book.douban.com/tag/?view=type'] #首先發(fā)送請求的url地址

    def parse(self, response): #實現(xiàn)提取數(shù)據(jù)等主要邏輯
        pass

??程序的基本框架搭建好后,就可以開始編寫獲取網(wǎng)頁信息的程序评腺。

1. 提取豆瓣圖書的大標簽帘瞭,小標簽

??在開發(fā)者工具的elements界面淑掌,可以通過對網(wǎng)頁的觀察定位到所需信息的xpath并進行相應(yīng)提取蒿讥。此外,大家也可使用爬蟲利器xpath helper進行定位抛腕。

??通過網(wǎng)頁標簽分析可以看出芋绸,大標題(小說,外國文學(xué)...)對應(yīng)了六塊大標簽担敌,每塊大標簽下存放了以行捆綁的中標簽摔敛,中標簽下才是我們所需要提取的小標簽(文學(xué),文化...)全封。因此想要提取到所有數(shù)據(jù)马昙,我們需要對響應(yīng)進行三次遍歷操作桃犬。

image

圖4.該6個div標簽下存放有標簽數(shù)據(jù)

image

圖5.每個小便簽按照每一行進行分組

image

圖6.每個td小標簽下有我們所需要的標簽數(shù)據(jù)和詳情頁地址

def parse(self, response):
    item = {}
    div_list = response.xpath(".//div[@class='article']/div[2]/div")  # 進行分組
    for div in div_list:
        item["big_title"] = div.xpath("./a/@name").extract_first()  # 提取大標簽
        tr_list = div.xpath(".//table[@class='tagCol']")  # 進行分組
        for tr in tr_list:
            td_list = tr.xpath(".//td")
            for td in td_list:
                item["small_title"] = td.xpath("./a/text()").extract_first()
                item["cate_list_url"] = td.xpath("./a/@href").extract_first()
image

圖7.我們所獲取到的大標簽、小標簽以及對應(yīng)的url地址

2.發(fā)送每個小標簽地址的請求行楞,獲取每個小標簽url地址的響應(yīng)

??從圖7可以看出攒暇,我們抓取的url地址不完整,因此需要對其進行補充子房,再分別發(fā)送請求形用。

if item["cate_list_url"] is not None:
    item["cate_list_url"] = 'https://book.douban.com' + item["cate_list_url"]
    yield scrapy.Request(
        item["cate_list_url"],
        callback=self.parse_list,
        meta={"item": deepcopy(item)}
        )
3. 提取書籍的數(shù)據(jù)

??在第2節(jié)中我們獲取了每個小標簽url地址的響應(yīng),接下來只需要新定義一個函數(shù)parse_list來處理響應(yīng)证杭,就可以抓取到所需數(shù)據(jù)田度。而這些數(shù)據(jù)中往往帶有換行符、制表符以及空格等我們所不需要的字符解愤,因此可以使用正則表達式進行處理镇饺,使最終提取的數(shù)據(jù)更為美觀。

def parse_list(self, response):
    item = response.meta["item"]
    li_list = response.xpath(".//ul[@class='subject-list']/li")  # 分組
    for li in li_list:
        item["book_name"] = li.xpath(".//div[@class='info']/h2/a/@title").extract_first()
        item["book_name"] = re.sub(r"[(\n)(\t)( )]", "", item["book_name"]) #刪除書名中的空格與換行符等
        item["book_score"] = li.xpath(".//div[@class='star clearfix']/span[@class='rating_nums']/text()").extract_first()
        book_detail_str = li.xpath(".//div[@class='info']//div[@class='pub']/text()").extract_first()
        book_detail_str = re.sub(r"[(\n)( )]", "", book_detail_str) #提取書籍簡要信息琢歇,并對簡要信息進行切片處理兰怠,提取切片中的內(nèi)容
        book_detail_list = list(book_detail_str.split("/"))
        item["book_price"] = book_detail_list[-1] if len(book_detail_list) > 0 else None
        item["book_author"] = book_detail_list[0] if len(book_detail_list) > 0 else None
        item["book_comment_nums"] = li.xpath(".//div[@class='star clearfix']/span[@class='pl']/text()").extract_first()
        item["book_comment_nums"] = re.sub(r"[(\n)( )]", "", item["book_comment_nums"])
        print(item)
image

圖8.數(shù)據(jù)簡要預(yù)覽

4 實現(xiàn)翻頁請求

??通過對網(wǎng)頁結(jié)構(gòu)進行分析,小編發(fā)現(xiàn)每一個小便簽下的圖書信息不止一頁李茫,因此需要設(shè)置翻頁請求揭保,定位到“下一頁”按鈕標簽后,同樣發(fā)現(xiàn)抓取的url地址不全魄宏,需要將地址補全秸侣。小編將發(fā)出翻頁請求所對應(yīng)的響應(yīng)(即callback)也放入parse_list函數(shù)。

image

圖9.每一頁數(shù)據(jù)爬取完畢需對下一頁進行請求

next_page = response.xpath(".//span[@class='next']/a/@href").extract_first()#提取url地址
if next_page is not None:#判斷宠互,如果還有下一頁味榛,就繼續(xù)發(fā)送請求
    next_page  = 'https://book.douban.com' + next_page
    yield scrapy.Request(
        next_page,
        callback=self.parse_list,#把發(fā)出的請求交給parse_list函數(shù)進行處理
        meta = {"item":deepcopy(item)}
        )
    yield item
5. 開啟管道,保存數(shù)據(jù)

??管道用于將爬取的數(shù)據(jù)保存到本地文件或數(shù)據(jù)庫中予跌。管道需要事先在settings.py文件中開啟搏色,將# Configure item pipelines下的注釋行解除,便可在pipeline.py中實現(xiàn)保存功能券册,本文以創(chuàng)建一個.txt文檔對數(shù)據(jù)進行保存為例频轿。

import json
class DoubanBooksPipeline:
    def process_item(self, item, spider):
        with open("douban_book_list.txt","a",encoding="utf-8") as f:
            f.write(json.dumps(item,ensure_ascii=False))
6. 運行項目,爬取數(shù)據(jù)

??完成上述設(shè)置后烁焙,就可運行項目抓取數(shù)據(jù)啦~運行項目僅需打開命令提示符航邢,輸入如下程序即可執(zhí)行:

scrapy crawl book

三、注意事項

??1.deepcopy是用于不同函數(shù)在多線程傳輸之中進行備份操作的行為骄蝇。由于數(shù)據(jù)公用一個item字典膳殷,在多線程操作中可能出現(xiàn)重復(fù)值的現(xiàn)象,利用deepcopy可以有效地解決item中出現(xiàn)重復(fù)值的問題九火。
??2.豆瓣具備一定反爬蟲赚窃,scrapy可能用同一個headers運行數(shù)秒就會被服務(wù)器監(jiān)測為爬蟲行為册招,需要利用一些反反爬蟲的操作。例如:在settings.py中設(shè)置一個USER_AGENT和IP池勒极,并在發(fā)送請求時隨機選擇一個USER_AGENT和IP跨细,便可以進行有效地偽裝,達到更完善的爬蟲效果河质。

??(ps:需要完整的程序可以關(guān)注微信公眾號:Stata and Python數(shù)據(jù)分析冀惭,并在后臺回復(fù)“豆瓣圖書”來獲取~)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市掀鹅,隨后出現(xiàn)的幾起案子散休,更是在濱河造成了極大的恐慌,老刑警劉巖乐尊,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件戚丸,死亡現(xiàn)場離奇詭異,居然都是意外死亡扔嵌,警方通過查閱死者的電腦和手機限府,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來痢缎,“玉大人胁勺,你說我怎么就攤上這事《揽酰” “怎么了署穗?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長嵌洼。 經(jīng)常有香客問我案疲,道長,這世上最難降的妖魔是什么麻养? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任褐啡,我火速辦了婚禮,結(jié)果婚禮上鳖昌,老公的妹妹穿的比我還像新娘备畦。我一直安慰自己,他們只是感情好遗遵,可當(dāng)我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布萍恕。 她就那樣靜靜地躺著逸嘀,像睡著了一般车要。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上崭倘,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天翼岁,我揣著相機與錄音类垫,去河邊找鬼。 笑死琅坡,一個胖子當(dāng)著我的面吹牛悉患,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播榆俺,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼售躁,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了茴晋?” 一聲冷哼從身側(cè)響起陪捷,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎诺擅,沒想到半個月后市袖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡烁涌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年苍碟,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片撮执。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡微峰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出抒钱,到底是詐尸還是另有隱情县忌,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布继效,位于F島的核電站症杏,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏瑞信。R本人自食惡果不足惜厉颤,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望凡简。 院中可真熱鬧逼友,春花似錦、人聲如沸秤涩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽筐眷。三九已至黎烈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背照棋。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工资溃, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人烈炭。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓溶锭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親符隙。 傳聞我的和親對象是個殘疾皇子趴捅,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,472評論 2 348