之前分享了很多
requests
、
selenium
的 Python 爬蟲文章,本文將
從原理到實戰
帶領大家入門另一個強大的框架
Scrapy
。
如果對
Scrapy
感興趣的話,不妨跟隨本文動手做一遍!
一、Scrapy框架簡介
Scrapy
是:由
Python
語言開發的一個快速、高層次的螢幕抓取和web抓取框架,用於抓取web站點並從頁面中提取結構化的數據,只需要實作少量的程式碼,就能夠快速的抓取。
二、執行原理
Scrapy框架的執行原理看下面一張圖就夠了( 事實上原理是比較復雜的,也不是三言兩語能夠說清楚的,因此感興趣的讀者可以進一步閱讀更多的相關文章來了解,本文不做過多講解 )
Scrapy主要包括了以下元件:
引擎(Scrapy Engine)
Item 計畫
排程器(Scheduler)
下載器(Downloader)
爬蟲(Spiders)
計畫管道(Pipeline)
下載器中介軟體(Downloader Middlewares)
爬蟲中介軟體(Spider Middlewares)
排程中介軟體(Scheduler Middewares)
三. 入門
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
爬蟲框架的具體使用步驟如下:
「
選擇目標網站
定義要抓取的數據(透過Scrapy Items來完成的)
編寫提取數據的spider
執行spider,獲取數據
數據儲存
五. 目錄檔說明
當我們建立了一個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] p 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
classMyspiderItem(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
classMyspiderPipeline:
defprocess_item(self, item, spider):
return item
這個檔也就是我們說的管道,當Item在Spider中被收集之後,它將會被傳遞到Item Pipeline(管道),這些Item Pipeline元件按定義的順序處理Item。每個Item Pipeline都是實作了簡單方法的Python類,比如決定此Item是丟棄而儲存。以下是item pipeline的一些典型套用:
驗證爬取的數據(檢查item包含某些欄位,比如說name欄位)
查重(並丟棄)
將爬取結果保存到檔或者資料庫中
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
classDbSpider(scrapy.Spider):
name = 'db'
allowed_domains = ['douban.com'] # 可以修改
start_urls = ['http://douban.com/'] # 開始的url也可以修改
defparse(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內容)
。
當shell載入後,將得到一個包含response數據的本地 response 變量,輸入
response.body
將輸出response的包體,輸出
response.headers
可以看到response的包頭。
輸入
response.selector
時, 將獲取到一個response 初始化的類 Selector 的物件,此時可以透過使用
response.selector.xpath()
或
response.selector.css()
來對 response 進行查詢。
Scrapy也提供了一些捷徑, 例如
response.xpath()
或
response.css()
同樣可以生效(如之前的案例)。
Selectors選擇器
「
Scrapy Selectors 內建 XPath 和 CSS Selector 運算式機制
」Selector有四個基本的方法,最常用的還是xpath:
xpath(): 傳入xpath運算式,返回該運算式所對應的所有節點的selector list列表
extract(): 序列化該節點為字串並返回list
css(): 傳入CSS運算式,返回該運算式所對應的所有節點的selector list列表,語法同 BeautifulSoup4
re(): 根據傳入的正規表式對數據進行提取,返回字串list列表
七、案例實戰
本節,我將使用Scrapy爬取站酷數據作為範例
7.1 案例說明
既然已經初步了解了scrapy的工作流程以及原理,我們來做一個入門的小案例,爬取站酷首頁推薦的item資訊。如下圖所示,一個小方框就是一個item資訊。我們要提取每一個item的六個組成部份:
imgLink(封面圖片連結);
title(標題);
types(型別);
vistor(人氣);
comment(評論數);
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
classZcoolItem(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檔裏面初步測試一下:
defparse(self, response):
divList = response.xpath('//div[@ class="work-list-box"]/div')
print(len(divList))
執行結果如下圖所示:
沒有問題,然後我們對各種資訊分別解析提取,
defparse(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提取數據方法:
S.N. | 方法 & 描述 |
---|---|
extract() | 返回的是符合要求的所有的數據,存在一個列表裏。 |
extract_first() | 返回的hrefs 列表裏的第一個數據。 |
get() | 和extract_first()方法返回的是一樣的,都是列表裏的第一個數據。 |
getall() | 和extract()方法一樣,返回的都是符合要求的所有的數據,存在一個列表裏。 |
註意:
「
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
classZcSpider(scrapy.Spider):
name = 'zc'
allowed_domains = ['zcool.com.cn']
start_urls = ['https://www.zcool.com.cn/home?p=1#tab_anchor'] # 第一頁的url
defparse(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
classZcoolPipeline:
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
defprocess_item(self, item, spider):
self.writer.writerow(dict(item)) # line5
print(item)
return item # line6
defclose_spider(self,spider):
self.f.close()
解釋:
line1: 開啟檔,指定方式為寫,利用第3個參數把csv寫數據時產生的空行消除
line2: 設定檔第一行的欄位名,註意要跟spider傳過來的字典key名稱相同
line3: 指定檔的寫入方式為csv字典寫入,參數1為指定具體檔,參數2為指定欄位名
line4: 寫入第一行欄位名,因為只要寫入一次,所以檔放在__init__裏面
line5: 寫入spider傳過來的具體數值,註意在spider檔中yield的item,是一個由類建立的例項物件,我們寫入數據時,寫入的是 字典,所以這裏還要轉化一下。
line6: 寫入完返回
7.6 程式執行
因為之前建立了start.py檔,並且對它就行了初始化設定,現在執行爬蟲程式不需要在控制台中輸入命令:
scrapy crawl zc(爬蟲計畫名)
直執行start.py檔:得到如下結果:
對應於頁面:
開啟csv檔如下圖所示:(由於csv檔在word中亂碼了,此處我是用Notepad++開啟)
沒有問題,數據采集完畢。
7.7. 總結
入門案例,需要細心,主要是基礎知識的鞏固,以便於為進階學習做好準備。
作者:
飲馬長江
來源 :早起Python
Crossin的新書【 碼上行動:用ChatGPT學會Python編程 】已經上市了。 本書以ChatGPT為輔助,系統全面地講解了如何掌握Python編程,適合Python零基礎入門的讀者學習。
購買後可加入讀者交流群,Crossin為你開啟陪讀模式,解答你在閱讀本書時的一切疑問。
Crossin的其他書籍:
添加微信 crossin123 ,加入編程教室共同學習 ~
感謝 轉發 和 點贊 的各位~