網(wǎng)絡(luò)爬蟲:使用Scrapy框架編寫一個(gè)抓取書籍信息的爬蟲服務(wù)

上周學(xué)習(xí)了BeautifulSoup的基礎(chǔ)知識(shí)并用它完成了一個(gè)網(wǎng)絡(luò)爬蟲( 使用Beautiful Soup編寫一個(gè)爬蟲 系列隨筆匯總)则果,
BeautifulSoup是一個(gè)非常流行的Python網(wǎng)絡(luò)抓取庫紫谷,它提供了一個(gè)基于HTML結(jié)構(gòu)的Python對象汗洒。
雖然簡單易懂美旧,又能非常好的處理HTML數(shù)據(jù),
但是相比Scrapy而言呼寸,BeautifulSoup有一個(gè)最大的缺點(diǎn):慢火的。

Scrapy 是一個(gè)開源的 Python 數(shù)據(jù)抓取框架,速度快麦轰,強(qiáng)大眷柔,而且使用簡單期虾。
來看一個(gè)官網(wǎng)主頁上的簡單并完整的爬蟲:


雖然只有10行左右的代碼,但是它的確是一個(gè)完整的爬蟲服務(wù):

  • 當(dāng)執(zhí)行scrapy runspider xxx.py命令的時(shí)候驯嘱, Scrapy在項(xiàng)目里查找Spider(蜘蛛???)并通過爬蟲引擎來執(zhí)行它。
  • 首先從定義在start_urls里的URL開始發(fā)起請求喳坠,然后通過parse()方法處理響應(yīng)鞠评。response參數(shù)就是返回的響應(yīng)對象。
  • 在parse()方法中壕鹉,通過一個(gè)CSS選擇器獲取想要抓取的數(shù)據(jù)剃幌。

Scrapy所有的請求都是異步的:

  • 也就是說Scrapy不需要等一個(gè)請求完成才能處理下一條請求,而是同時(shí)發(fā)起另一條請求晾浴。
  • 而且负乡,異步請求的另一個(gè)好處是當(dāng)某個(gè)請求失敗了,其他的請求不會(huì)受到影響脊凰。

安裝(Mac)

pip install scrapy

其他操作系統(tǒng)請參考完整安裝指導(dǎo):
http://doc.scrapy.org/en/latest/intro/install.html

Scrapy中幾個(gè)需要了解的概念

Spiders

Spider類想要表達(dá)的是:如何抓取一個(gè)確定了的網(wǎng)站的數(shù)據(jù)抖棘。比如在start_urls里定義的去哪個(gè)鏈接抓取,parse()方法中定義的要抓取什么樣的數(shù)據(jù)狸涌。
當(dāng)一個(gè)Spider開始執(zhí)行的時(shí)候切省,它首先從start_urls()中的第一個(gè)鏈接開始發(fā)起請求,然后在callback里處理返回的數(shù)據(jù)帕胆。

Items

Item類提供格式化的數(shù)據(jù)朝捆,可以理解為數(shù)據(jù)Model類。

Selectors

Scrapy的Selector類基于lxml庫懒豹,提供HTML或XML轉(zhuǎn)換功能芙盘。以response對象作為參數(shù)生成的Selector實(shí)例即可通過實(shí)例對象的xpath()方法獲取節(jié)點(diǎn)的數(shù)據(jù)。

編寫一個(gè)Web爬蟲

接下來將上一個(gè)Beautiful Soup版的抓取書籍信息的例子( 使用Beautiful Soup編寫一個(gè)爬蟲 系列隨筆匯總)改寫成Scrapy版本脸秽。

新建項(xiàng)目

scrapy startproject book_project

這行命令會(huì)創(chuàng)建一個(gè)名為book_project的項(xiàng)目儒老。

編寫Item類

即實(shí)體類,代碼如下:

import scrapy

class BookItem(scrapy.Item):
    title = scrapy.Field()
    isbn = scrapy.Field()
    price = scrapy.Field()

編寫Spider類

設(shè)置這個(gè)Spider的名稱豹储,允許爬取的域名和從哪個(gè)鏈接開始:

class BookInfoSpider(scrapy.Spider):
    name = "bookinfo"
    allowed_domains = ["allitebooks.com", "amazon.com"]
    start_urls = [
        "http://www.allitebooks.com/security/",
    ]
遍歷分頁數(shù)據(jù)
def parse(self, response):
    # response.xpath('//a[contains(@title, "Last Page →")]/@href').re(r'(\d+)')[0]
    num_pages = int(response.xpath('//a[contains(@title, "Last Page →")]/text()').extract_first())
    base_url = "http://www.allitebooks.com/security/page/{0}/"
    for page in range(1, num_pages):
        yield scrapy.Request(base_url.format(page), dont_filter=True, callback=self.parse_page)
從allitebooks.com獲取書籍信息方法
def parse_page(self, response):
    for sel in response.xpath('//div/article'):
        book_detail_url = sel.xpath('div/header/h2/a/@href').extract_first()
        yield scrapy.Request(book_detail_url, callback=self.parse_book_info)

def parse_book_info(self, response):
    title = response.css('.single-title').xpath('text()').extract_first()
    isbn = response.xpath('//dd[2]/text()').extract_first()
    item = BookItem()
    item['title'] = title
    item['isbn'] = isbn
    amazon_search_url = 'https://www.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Daps&field-keywords=' + isbn
    yield scrapy.Request(amazon_search_url, callback=self.parse_price, meta={ 'item': item })

'//a'的意思所有的a標(biāo)簽贷盲;
'//a[contains(@title, "Last Page →")' 的意思是在所有的a標(biāo)簽中,title屬性包涵"Last Page →"的a標(biāo)簽剥扣;
extract() 方法解析并返回符合條件的節(jié)點(diǎn)數(shù)據(jù)巩剖。

從amazon.com獲取書籍價(jià)格方法
def parse_price(self, response):
    item = response.meta['item']
    item['price'] = response.xpath('//span/text()').re(r'\$[0-9]+\.[0-9]{2}?')[0]
    yield item

啟動(dòng)服務(wù)

scrapy crawl bookinfo -o books.csv

-o books.csv 參數(shù)的意思是將抓取的Item集合輸出到csv文件。

除了CSV格式钠怯,Scrapy還支持JSON佳魔,XML的格式輸入。具體請參考:
http://doc.scrapy.org/en/latest/topics/feed-exports.html#topics-feed-exports

結(jié)果:

完整代碼請移步GitHub:
https://github.com/backslash112/book_scraper_scrapy
我們處于大數(shù)據(jù)時(shí)代晦炊,對數(shù)據(jù)處理感興趣的朋友歡迎查看另一個(gè)系列隨筆:
利用Python進(jìn)行數(shù)據(jù)分析 基礎(chǔ)系列隨筆匯總

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鞠鲜,一起剝皮案震驚了整個(gè)濱河市宁脊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌贤姆,老刑警劉巖榆苞,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異霞捡,居然都是意外死亡坐漏,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進(jìn)店門碧信,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赊琳,“玉大人,你說我怎么就攤上這事砰碴□锓ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵呈枉,是天一觀的道長趁尼。 經(jīng)常有香客問我,道長碴卧,這世上最難降的妖魔是什么弱卡? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮住册,結(jié)果婚禮上婶博,老公的妹妹穿的比我還像新娘。我一直安慰自己荧飞,他們只是感情好凡人,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著叹阔,像睡著了一般挠轴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上耳幢,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天岸晦,我揣著相機(jī)與錄音,去河邊找鬼睛藻。 笑死启上,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的店印。 我是一名探鬼主播冈在,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼按摘!你這毒婦竟也來了包券?” 一聲冷哼從身側(cè)響起纫谅,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎溅固,沒想到半個(gè)月后付秕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡发魄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年盹牧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片励幼。...
    茶點(diǎn)故事閱讀 38,654評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖口柳,靈堂內(nèi)的尸體忽然破棺而出苹粟,到底是詐尸還是另有隱情,我是刑警寧澤跃闹,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布嵌削,位于F島的核電站,受9級特大地震影響望艺,放射性物質(zhì)發(fā)生泄漏苛秕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一找默、第九天 我趴在偏房一處隱蔽的房頂上張望艇劫。 院中可真熱鬧,春花似錦惩激、人聲如沸店煞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽顷蟀。三九已至,卻和暖如春骡技,著一層夾襖步出監(jiān)牢的瞬間鸣个,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工布朦, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留囤萤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓喝滞,卻偏偏與公主長得像阁将,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子右遭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內(nèi)容