學(xué)會運(yùn)用爬蟲框架 Scrapy (三)

圖片來自 unsplash

上篇文章介紹 Scrapy 框架爬取網(wǎng)站的基本用法秆麸。但是爬蟲程序比較粗糙,很多細(xì)節(jié)還需打磨及汉。本文主要是講解 Scrapy 一些小技巧,能讓爬蟲程序更加完善坷随。

1 設(shè)置 User-agent

Scrapy 官方建議使用 User-Agent 池, 輪流選擇其中一個常用瀏覽器的 User-Agent來作為 User-Agent驻龟。scrapy 發(fā)起的 http 請求中 headers 部分中 User-Agent 字段的默認(rèn)值是Scrapy/VERSION (+http://scrapy.org),我們需要修改該字段偽裝成瀏覽器訪問網(wǎng)站缸匪。

  1. 同樣在 setting.py 中新建存儲 User-Agent 列表,
UserAgent_List = [
    "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2226.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 6.4; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2225.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2225.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2224.3 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93 Safari/537.36",
    "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 4.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.67 Safari/537.36",
    "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.67 Safari/537.36",
    "Mozilla/5.0 (X11; OpenBSD i386) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1944.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.3319.102 Safari/537.36",
    "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.2309.372 Safari/537.36",
    "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.2117.157 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36",
    "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1866.237 Safari/537.36",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.137 Safari/4E423F",
    "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1",
    "Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10; rv:33.0) Gecko/20100101 Firefox/33.0",
    "Mozilla/5.0 (X11; Linux i586; rv:31.0) Gecko/20100101 Firefox/31.0",
    "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20130401 Firefox/31.0",
    "Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0",
    "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16",
    "Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.14",
    "Mozilla/5.0 (Windows NT 6.0; rv:2.0) Gecko/20100101 Firefox/4.0 Opera 12.14",
    "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0) Opera 12.14",
    "Opera/9.80 (Windows NT 5.1; U; zh-sg) Presto/2.9.181 Version/12.00"
]
  1. 在 middlewares.py 文件中新建一個名為RandomUserAgentMiddleware的代理中間層類
import random

from scrapy_demo.settings import UserAgent_List

class RandomUserAgentMiddleware(object):
    '''動態(tài)隨機(jī)設(shè)置 User-agent'''
    def process_request(self, request, spider):

        ua = random.choice(UserAgent_List)
        if ua:
            request.headers.setdefault('User-Agent', ua)
            print(request.headers)
  1. 在 settings.py 中配置 RandomUserAgentMiddleware , 激活中間件
DOWNLOADER_MIDDLEWARES = {

    # 第二行的填寫規(guī)則
    #  yourproject.middlewares(文件名).middleware類

    # 設(shè)置 User-Agent
    'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware': None,
    'scrapy_demo.middlewares.RandomUserAgentMiddleware': 400,  # scrapy_demo 是你項(xiàng)目的名稱
}

2 禁用cookies

有些站點(diǎn)會使用 cookies 來發(fā)現(xiàn)爬蟲的軌跡凌蔬。因此,我們最好禁用 cookies

在 settings.py 文件中新增以下配置懈词。

# 默認(rèn)是被注釋的, 也就是運(yùn)行使用 cookies
# Disable cookies (enabled by default)
COOKIES_ENABLED = False

3 設(shè)置下載延遲

當(dāng) scrapy 的下載器在下載同一個網(wǎng)站下一個頁面前需要等待的時間辩诞。我們設(shè)置下載延遲, 可以有效避免下載器獲取到下載地址就立刻執(zhí)行下載任務(wù)的情況發(fā)生。從而可以限制爬取速度, 減輕服務(wù)器壓力荞怒。

在 settings.py 文件中新增以下配置秧秉。

# 默認(rèn)是被注釋的
# Configure a delay for requests for the same website (default: 0)
# See http://scrapy.readthedocs.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
DOWNLOAD_DELAY = 3 
# 單位是秒,  上述設(shè)置是延遲 3s。 
# 同時還支持設(shè)置小數(shù), 例 0.3, 延遲 300 ms

4 設(shè)置代理

有些網(wǎng)站設(shè)置反爬蟲機(jī)制荧嵌,這使得我們的爬蟲程序可能爬到一定數(shù)量網(wǎng)頁就爬取不下去了砾淌。我們需要裝飾下爬蟲,讓它訪問網(wǎng)站行為更像類人行為赃春。使用 IP 代理池能突破大部分網(wǎng)站的限制劫乱。

  1. 我們可以通過國內(nèi)一些知名代理網(wǎng)站(例如:迅代理衷戈、西刺代理)獲取代理服務(wù)器地址。

我將自己收集一些代理地址以列表形式保存到 settings.py 文件中

# 代理地址具有一定的使用期限, 不保證以下地址都可用殖妇。
PROXY_LIST = [
    "https://175.9.77.240:80",
    "http://61.135.217.7:80",
    "http://113.77.101.113:3128"
    "http://121.12.42.180:61234",
    "http://58.246.59.59:8080",
    "http://27.40.144.98:808",
    "https://119.5.177.167:4386",
    "https://210.26.54.43:808",
]
  1. 在 middlewares.py 文件中新建一個名為ProxyMiddleware的代理中間層類
import random

from scrapy_demo.settings import PROXY_LIST

class ProxyMiddleware(object):
    # overwrite process request
    def process_request(self, request, spider):
        # Set the location of the proxy
        # request.meta['proxy'] = "https://175.9.77.240:80"
        request.meta['proxy'] = random.choice(PROXY_LIST)
  1. 在 settings.py 文件中增加代理配置:
DOWNLOADER_MIDDLEWARES = {

    # 第二行的填寫規(guī)則
    #  yourproject.middlewares(文件名).middleware類

    # 設(shè)置代理
    'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware': 110,
    'scrapy_demo.middlewares.ProxyMiddleware': 100,  # scrapy_demo 是你項(xiàng)目的名稱
}

除此之外,如果你比較狠的話座每,可以采用 VPN + Tor 方式來突破反爬蟲機(jī)制摘悴。

5 減小下載超時

如果您對一個非常慢的連接進(jìn)行爬取(一般對通用爬蟲來說并不重要), 減小下載超時能讓卡住的連接能被快速的放棄并解放處理其他站點(diǎn)的能力。

在 settings.py 文件中增加配置:

DOWNLOAD_TIMEOUT = 15

6 頁面跟隨規(guī)則

在爬取網(wǎng)站時叉橱,可能一些頁面是我們不想爬取的者蠕。如果使用 最基本的 Spider,它還是會將這些頁面爬取下來踱侣。因此,我們需要使用更加強(qiáng)大的爬取類CrawlSpider探膊。

我們的爬取類繼承 CrawlSpider待榔,必須新增定義一個 rules 屬性。rules 是一個包含至少一個 Rule(爬取規(guī)則)對象的 list腌闯。 每個 Rule 對爬取網(wǎng)站的動作定義了特定表現(xiàn)雕憔。CrawlSpider 也是繼承 Spider 類,所以具有Spider的所有函數(shù)分瘦。

Rule 對象的構(gòu)造方法如下:

Rule(link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None)

我們在使用 Rule 一般只會用到前面幾個參數(shù)畅卓,它們作用如下:

  • link_extractor: 它是一個 Link Extractor 對象翁潘。 其定義了如何從爬取到的頁面提取鏈接。
    link_extractor既可以自己定義渗勘,也可以使用已有LinkExtractor類,主要參數(shù)為:
    • allow:滿足括號中“正則表達(dá)式”的值會被提取乔遮,如果為空取刃,則全部匹配。
    • deny:與這個正則表達(dá)式(或正則表達(dá)式列表)不匹配的 Url 一定不提取坯辩。
    • allow_domains:會被提取的鏈接的domains崩侠。
    • deny_domains:一定不會被提取鏈接的domains。
    • restrict_xpaths:使用xpath表達(dá)式改抡,和allow共同作用過濾鏈接系瓢。還有一個類似的restrict_css
  • callback:從 link_extractor 中每獲取到鏈接時將會調(diào)用該函數(shù)。它指定一個回調(diào)方法阵赠。會返回一個包含 Item 對象的列表肌稻。

  • follow:它 是一個布爾(boolean)值,指定了根據(jù)該規(guī)則從 response 提取的鏈接是否需要跟進(jìn)枷邪。 如果 callback 為None诺凡, follow 默認(rèn)設(shè)置為 True 腹泌,否則默認(rèn)為 False 。

  • process_links:從link_extractor中獲取到鏈接列表時將會調(diào)用該函數(shù)芥吟。它同樣需要指定一個方法,該方法主要用來過濾 Url钟鸵。

我以爬取豆瓣電影 Top 250 頁面為例子進(jìn)行講解如何利用 rules 進(jìn)行翻頁爬取棺耍。


在頁面的底部,有這樣的分頁俊卤。我們想通過抓取翻頁 url 進(jìn)行下一個頁面爬取害幅。

點(diǎn)擊查看大圖

通過分析頁面可知矫限,鏈接的規(guī)則是

https://movie.douban.com/top250?start=當(dāng)前分頁第一個電影序號&filter=分頁數(shù)

我使用 xpath 來匹配佩抹,當(dāng)然你也可以使用正則表達(dá)式或者 CSS 選擇器。rules 可以這樣定義:

rules = (
    Rule(LinkExtractor(allow=(), restrict_xpaths=('//div[@class="paginator"]',)),
         follow=True,
         callback='parse_item',
         process_links='process_links',
         ),
)

完整的 spider 代碼如下:

# -*- coding: utf-8 -*-
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor


class DoubanTop250(CrawlSpider):
    name = 'movie_douban'
    allowed_domains = ['douban.com']
    start_urls = ["https://movie.douban.com/top250"]


    rules = (
        Rule(LinkExtractor(allow=(), restrict_xpaths=('//div[@class="paginator"]',)),
             follow=True,
             callback='parse_item',
             process_links='process_links',
             ),
    )

    def parse_item(self, response):
            # 解析 response, 將其轉(zhuǎn)化為 item
            yield item

另外,LinkExtractor 參數(shù)中的 allow() 和 deny() 枢里,我們也是經(jīng)常使用到份乒。規(guī)定爬取哪些頁面是否要進(jìn)行爬取世舰。

7 動態(tài)創(chuàng)建Item類

對于有些應(yīng)用廓奕,item的結(jié)構(gòu)由用戶輸入或者其他變化的情況所控制珊膜。我們可以動態(tài)創(chuàng)建class嚼沿。

from scrapy.item import DictItem, Field

def create_item_class(class_name, field_list):
    fields = {
        field_name: Field() for field_name in field_list
    }
    return type(class_name, (DictItem,), {'fields': fields})

系列文章:
學(xué)會運(yùn)用爬蟲框架 Scrapy (一)
學(xué)會運(yùn)用爬蟲框架 Scrapy (二)
學(xué)會運(yùn)用爬蟲框架 Scrapy (四) —— 高效下載圖片
學(xué)會運(yùn)用爬蟲框架 Scrapy (五) —— 部署爬蟲

推薦閱讀:
爬蟲實(shí)戰(zhàn)二:爬取電影天堂的最新電影
爬蟲與反爬蟲的博弈
爬蟲系列的總結(jié)


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末骡尽,一起剝皮案震驚了整個濱河市攀细,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌辨图,老刑警劉巖故河,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異理盆,居然都是意外死亡凑阶,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來师郑,“玉大人,你說我怎么就攤上這事张遭〉乩妫” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵洁闰,是天一觀的道長渴庆。 經(jīng)常有香客問我雅镊,道長,這世上最難降的妖魔是什么耸弄? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任卓缰,我火速辦了婚禮,結(jié)果婚禮上捌显,老公的妹妹穿的比我還像新娘。我一直安慰自己理肺,他們只是感情好善镰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布炫欺。 她就那樣靜靜地躺著,像睡著了一般树姨。 火紅的嫁衣襯著肌膚如雪桥状。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機(jī)與錄音砾肺,去河邊找鬼防嗡。 笑死,一個胖子當(dāng)著我的面吹牛裙盾,可吹牛的內(nèi)容都是我干的他嫡。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼徘熔,長吁一口氣:“原來是場噩夢啊……” “哼酷师!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起山孔,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤台颠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后譬挚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體酪呻,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡玩荠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年阶冈,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片女坑。...
    茶點(diǎn)故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡匆骗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出盟广,到底是詐尸還是另有隱情瓮钥,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布桨武,位于F島的核電站锈津,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏七咧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一爆存、第九天 我趴在偏房一處隱蔽的房頂上張望先较。 院中可真熱鬧悼粮,春花似錦、人聲如沸扣猫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽勺远。三九已至时鸵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間初坠,已是汗流浹背囊拜。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工冠跷, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留身诺,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓橄务,卻偏偏與公主長得像穴亏,于是被迫代替她去往敵國和親重挑。 傳聞我的和親對象是個殘疾皇子棠涮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評論 2 355

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