從原理到實戰,一份詳實的 Scrapy 爬蟲教程

大家好,我是早起。

之前分享了很多 requestsselenium 的 Python 爬蟲文章,本文將從原理到實戰帶領大家入門另一個強大的框架 Scrapy。如果對Scrapy感興趣的話,不妨跟隨本文動手做一遍!

一、Scrapy 框架簡介

Scrapy是: 由Python語言開發的一個快速、高層次的屏幕抓取和 web 抓取框架,用於抓取 web 站點並從頁面中提取結構化的數據,只需要實現少量的代碼,就能夠快速的抓取。

二、運行原理

Scrapy 框架的運行原理看下面一張圖就夠了(事實上原理是比較複雜的,也不是三言兩語能夠說清楚的,因此感興趣的讀者可以進一步閱讀更多的相關文章來了解,本文不做過多講解

Scrapy 主要包括了以下組件:

三. 入門

3.1 安裝

第一種:在命令行模式下使用 pip 命令即可安裝:

$ pip install scrapy

第二種:首先下載,然後再安裝:

$ pip download scrapy -d ./
# 通過指定國內鏡像源下載 
$pip download  -i https://pypi.tuna.tsinghua.edu.cn/simple scrapy -d ./

進入下載目錄後執行下面命令安裝:

$ pip install Scrapy-1.5.0-py2.py3-none-any.whl

3.2 使用

使用大概分爲下面四步 1 創建一個 scrapy 項目

scrapy startproject mySpider

2 生成一個爬蟲

scrapy genspider demo "demo.cn"

3 提取數據

完善spider 使用xpath等

4 保存數據

pipeline中保存數據

3.3 程序運行

在命令中運行爬蟲

scrapy crawl qb     # qb爬蟲的名字

在 pycharm 中運行爬蟲

from scrapy import cmdline
cmdline.execute("scrapy crawl qb".split())

四、基本步驟

Scrapy 爬蟲框架的具體使用步驟如下:

  1. 選擇目標網站

  2. 定義要抓取的數據(通過 Scrapy Items 來完成的)

  3. 編寫提取數據的 spider

  4. 執行 spider,獲取數據

  5. 數據存儲

五. 目錄文件說明

當我們創建了一個 scrapy 項目後, 繼續創建了一個 spider, 目錄結構是這樣的:

下面來簡單介紹一下各個主要文件的作用:

scrapy.cfg :項目的配置文件

mySpider/ :項目的 Python 模塊,將會從這裏引用代碼

mySpider/items.py :項目的目標文件

mySpider/pipelines.py :項目的管道文件

mySpider/settings.py :項目的設置文件

mySpider/spiders/ :存儲爬蟲代碼目錄

5.1 scrapy.cfg 文件

項目配置文件。這個是文件的內容:

# Automatically created by: scrapy startproject
#
# For more information about the [deploy] section see:
# https://scrapyd.readthedocs.io/en/latest/deploy.html

[settings]
default = mySpider.settings

[deploy]
#url = http://localhost:6800/
project = mySpider

5.2 mySpider**/**

項目的 Python 模塊,將會從這裏引用代碼

5.3 mySpider/items.py

項目的目標文件

# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy

class MyspiderItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    pass

定義 scrapy items 的模塊, 示例: name = scrapy.Field()

5.4 mySpider/pipelines.py

項目的管道文件

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html


# useful for handling different item types with a single interface
from itemadapter import ItemAdapter


class MyspiderPipeline:
    def process_item(self, item, spider):
        return item

這個文件也就是我們說的管道, 當 Item 在 Spider 中被收集之後,它將會被傳遞到 Item Pipeline(管道),這些 Item Pipeline 組件按定義的順序處理 Item。每個 Item Pipeline 都是實現了簡單方法的 Python 類,比如決定此 Item 是丟棄而存儲。以下是 item pipeline 的一些典型應用:

5.5 mySpider/settings.py

項目的設置文件

# Scrapy settings for mySpider project
...

BOT_NAME = 'mySpider' # scrapy項目名

SPIDER_MODULES = ['mySpider.spiders']
NEWSPIDER_MODULE = 'mySpider.spiders'
.......

# Obey robots.txt rules
ROBOTSTXT_OBEY = False # 是否遵守協議,一般給位false,但是創建完項目是是True,我們把它改爲False

# Configure maximum concurrent requests performed by Scrapy (default: 16)
#CONCURRENT_REQUESTS = 32 # 最大併發量 默認16
......
#DOWNLOAD_DELAY = 3 # 下載延遲 3秒

# Override the default request headers: # 請求報頭,我們打開
DEFAULT_REQUEST_HEADERS = {
  'Accept''text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  'Accept-Language''en',
}
# 爬蟲中間件
#SPIDER_MIDDLEWARES = {
#    'mySpider.middlewares.MyspiderSpiderMiddleware': 543,
#}

# 下載中間件
#DOWNLOADER_MIDDLEWARES = {
#    'mySpider.middlewares.MyspiderDownloaderMiddleware': 543,
#}
......
# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
#ITEM_PIPELINES = {
#    'mySpider.pipelines.MyspiderPipeline': 300, # 管道
#}
.......

省略號省略代碼, 一般重要點, 給了註釋

6.mySpider/spiders/ :存儲爬蟲代碼目錄

import scrapy

class DbSpider(scrapy.Spider):
    name = 'db'
    allowed_domains = ['douban.com'] # 可以修改
    start_urls = ['http://douban.com/'] # 開始的url也可以修改

    def parse(self, response):
        # pass

六. Scrapy shell

Scrapy 終端是一個交互終端,我們可以在未啓動 spider 的情況下嘗試及調試代碼,也可以用來測試 XPath 或 CSS 表達式,查看他們的工作方式,方便我們爬取的網頁中提取的數據, 但是一般使用的不多。感興趣的查看官方文檔:

官方文檔

http://scrapy-chs.readthedocs.io/zh_CN/latest/topics/shell.html

Scrapy Shell 根據下載的頁面會自動創建一些方便使用的對象,例如 Response 對象,以及 Selector 對象 (對HTML及XML內容)

Selectors 選擇器

Scrapy Selectors 內置 XPathCSS Selector 表達式機制

Selector 有四個基本的方法,最常用的還是 xpath:

七、案例實戰

本節,我將使用 Scrapy 爬取站酷數據作爲示例

7.1 案例說明

既然已經初步瞭解了 scrapy 的工作流程以及原理, 我們來做一個入門的小案例, 爬取站酷首頁推薦的 item 信息。如下圖所示,一個小方框就是一個 item 信息。我們要提取每一個 item 的六個組成部分:

  1. imgLink(封面圖片鏈接);

  2. title(標題);

  3. types(類型);

  4. vistor(人氣);

  5. comment(評論數);

  6. likes(推薦人數)

然後只是一個頁面的 item,我們還要通過翻頁實現批量數據採集。

7.2 文件配置

目錄結構

在上一篇中我們說明了新建 scrapy 項目(zcool) spider 項目(zc),這裏不再贅述,然後得到我們的目錄結構如下圖所示:

start.py 文件

然後爲了方便運行,在 zcool 目錄下新建 start 文件。並進行初始化設置。

from scrapy import cmdline
cmdline.execute('scrapy crawl zc'.split())

settings.py 文件

在這個文件裏我們需要做幾樣設置👇

避免在程序運行的時候打印 log 日誌信息

  LOG_LEVEL = 'WARNING'
 ROBOTSTXT_OBEY = False

添加請求頭:

打開管道:

item.py 文件

import scrapy

class ZcoolItem(scrapy.Item):
    # define the fields for your item here like:
    imgLink = scrapy.Field() # 封面圖片鏈接
    title = scrapy.Field() # 標題
    types = scrapy.Field() # 類型
    vistor = scrapy.Field() # 人氣
    comment = scrapy.Field() # 評論數
    likes = scrapy.Field() # 推薦人數

7.3 頁面數據提取

首先我們在站酷頁面使用 xpath-helper 測試一下:

然後 zc.py 文件裏面初步測試一下:

def parse(self, response):
    divList = response.xpath('//div[@class="work-list-box"]/div')
    print(len(divList))

運行結果如下圖所示:

沒有問題,然後我們對各種信息分別解析提取,

def parse(self, response):
    divList = response.xpath('//div[@class="work-list-box"]/div')
    for div in divList:
        imgLink = div.xpath("./div[1]/a/img/@src").extract()[0] # 1.封面圖片鏈接
  ...  2.title(標題);3 types(類型);4vistor(人氣);5comment(評論數)  ....
        likes = div.xpath("./div[2]/p[3]/span[3]/@title").extract_first() # 6likes(推薦人數)

        item = ZcoolItem(imgLink=imgLink,title=title,types=types,vistor=vistor,comment=comment,likes=likes)

        yield item

解釋: xpath 提取數據方法:

eQzrWF

注意:

get() 、getall() 方法是新的方法,extract() 、extract_first() 方法是舊的方法。extract() 、extract_first() 方法取不到就返回 None。get() 、getall() 方法取不到就 raise 一個錯誤。

item 實例創建(yield 上面一行代碼)

這裏我們之前在目錄文件配置的 item 文件中已經進行了設置,對於數據存儲,我們在爬蟲文件中開頭要導入這個類:

from zcool.items import ZcoolItem

然後使用 yield 返回數據。

爲什麼使用 yield 而不是 return

不能使用 return 這個無容置疑,因爲要翻頁,使用 return 直接退出函數;而對於 yield: 在調用 for 的時候,函數內部不會立即執行,只是返回了一個生成器對象。在迭代的時候函數會開始執行,當在 yield 的時候,會返回當前值 (i)。之後的這個函數會在循環中進行,直到沒有下一個值。

7.4 翻頁實現批量數據採集

通過上面的代碼已經可以初步實現數據採集,只不過只有第一頁的,如下圖所示:

但是我們的目標是 100 個頁面的批量數據採集,所以代碼還需要修改。針對翻頁這裏介紹兩種方式:

方式一:我們首先在頁面中定位到下一頁的按鈕,如下圖所示:

然後編寫如下代碼,在 for 循環完畢後。

next_href = response.xpath("//a[@class='laypage_next']/@href").extract_first()
if next_href:
    next_url = response.urljoin(next_href)
    print('*' * 60)
    print(next_url)
    print('*' * 60)
    request = scrapy.Request(next_url)
    yield request

scrapy.Request(): 把下一頁的 url 傳遞給 Request 函數, 進行翻頁循環數據採集。

https://www.cnblogs.com/heymonkey/p/11818495.html # scrapy.Request()參考鏈接

注意方式一隻有下一頁按鈕它的 href 對應屬性值和下一頁的 url 一致纔行。

方式二:定義一個全局變量 count = 0, 每爬取一頁數據,令其加一,構建新的 url, 再使用 scrapy.Request() 發起請求。

如下圖所示:

count = 1

class ZcSpider(scrapy.Spider):
    name = 'zc'
    allowed_domains = ['zcool.com.cn']
    start_urls = ['https://www.zcool.com.cn/home?p=1#tab_anchor'] # 第一頁的url

    def parse(self, response):
        global count
        count += 1
        
        for div in divList:
    # ...xxx...
            yield item

        next_url = 'https://www.kuaikanmanhua.com/tag/0?state=1&sort=1&page={}'.format(count)
        yield scrapy.Request(next_url)

這兩種方式在實際案例中擇機採用。

7.5 數據存儲

數據存儲是在 pipline.py 中進行的, 代碼如下:

from itemadapter import ItemAdapter
import csv

class ZcoolPipeline:
    def __init__(self): 
        self.f = open('Zcool.csv','w',encoding='utf-8',newline='')       # line1
        self.file_name = ['imgLink''title','types','vistor','comment','likes']  # line2
        self.writer = csv.DictWriter(self.f, fieldnames=self.file_name)     # line3
        self.writer.writeheader()              # line4

    def process_item(self, item, spider):
        self.writer.writerow(dict(item))              # line5
        print(item)
        return item                  # line6 

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

解釋:

7.6 程序運行

因爲之前創建了 start.py 文件, 並且對它就行了初始化設置,現在運行爬蟲程序不需要在控制檯中輸入命令:

scrapy crawl zc(爬蟲項目名)

直運行 start.py 文件:得到如下結果:

對應於頁面:

打開 csv 文件如下圖所示:(由於 csv 文件在 word 中亂碼了,此處我是用 Notepad++ 打開)

沒有問題,數據採集完畢。

7.7. 總結

入門案例,需要細心,主要是基礎知識的鞏固,以便於爲進階學習做好準備。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/0dF8lQftelkDjd2_SKKAlQ