第70天: Python Scrapy 爬蟲框架及搭建


by 戴景波

Scrapy 框架實現爬蟲的基本原理

Scrapy 就是封裝好的框架,你可以專心編寫爬蟲的核心邏輯,無需自己編寫與爬蟲邏輯無關的代碼,套用這個框架就可以實現以上功能——爬取到想要的數據。

Scrapy是一個Python實現的輕量級爬蟲框架,它借助Twisted實現異步抓取。

Scrapy 是一個為了爬取網站數據,提取結構性數據而編寫的應用框架。 可以應用在包括數據挖掘,信息處理或存儲歷史數據等一系列的程序中。

本文檔將通過介紹Scrapy背后的概念使您對其工作原理有所了解,如果暫時理解不深也沒關系,后邊會結合實例具體介紹。

Python 爬蟲基本流程

A 發起請求———B 解析內容———C 獲取響應內容———D 保存數據

A 通過 HTTP 向目標站點發起請求,即發送一個 Request ,請求可以包含額外的 headers 等信息,等待服務器響應。

B 得到的內容可能是 HTML ,可以用正則表達式、網頁解析庫進行解析。可能是 Json ,可以直接轉為 Json 對象解析,可能是二進制數據,可以做保存或者進一步的處理。

C 如果服務器能正常響應,會得到一個 Response , Response 的內容便是所要獲取的頁面內容,類型可能有 HTML , Json 字符串,二進制數據(如圖片視頻)等類型。

D 保存形式多樣,可以存為文本,也可以保存至數據庫,或者保存特定格式的文件。

搭建自己本機環境如下:Windows7 64bit———Python3.7———Pycharm64

安裝 Python———安裝 Pycharm———安裝 Scrapy———新建爬蟲項目

簡單解釋:將 Python 比作 Java ,那么 Pycharm 就相當於 eclipse , Pycharm 就是 Python 語言的運行環境 IDE 工具。

安裝 Python

在 Python 的官網 www.python.org 中找到最新版本的 Python 安裝包,點擊進行下載,請注意,當你的電腦是32位的機器,請選擇32位的安裝包,如果是64位的,請選擇64位的安裝包;

我自己機器是 win7 64bit 所以我下載的是 python-3.7.4.amd64.exe,其中的 add python 3.7 to PATH 一定要勾選。

另外安裝 python 路徑不要有中文和空格,避免以后麻煩。后邊就點擊下一步即可。

如果忘記勾選則需要手動添加環境變量:(需要添加兩個: c:\python3.7.0;c:\python3.7.0\Scripts)

右鍵計算機——點擊屬性——點擊高級系統設置——高級——環境變量——用戶變量——PATH 添加自己安裝 python 的路徑。

安裝 Pycharm

本篇對於環境的搭建只是起到拋磚引玉的作用,建議大家以下邊做參考。

https://www.runoob.com/w3cnote/pycharm-windows-install.html

安裝 Scrapy

由於安裝 Scrapy 不是本系列重點,所以僅展示 Windows 系統上安裝 Scrapy 的步驟。注意:一定按順序安裝。 Cmd 進入 dos 窗口:

C:\Users\Administrator>python
Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
C:\Users\Administrator>python -m pip -V
pip 19.0.3 from c:\python3.7.0\lib\site-packages\pip (python 3.7)  
1.python -m pip install --upgrade pip
2.python -m pip install Twisted-18.9.0-cp37-cp37m-win_amd64.whl
3.python -m pip install pypiwin32
4.python -m pip install scrapy
5.python -m pip install requests

如果中途安裝遇到問題請及時 Google 查閱資料,查閱就是積累的過程。

Scrapy 創建新項目:

Pycharm 中用 alt+F12 切換到命令行,在命令行輸入:

(venv2) E:\>scrapy startproject peilv

就會生成 Scrapy 項目,項目名稱是 peilv ,結構如下:主要改寫2個文件:“items、settings”,新增2個文件:“爬蟲主程序”、itemcsvexporter。

peilv
scrapy.cfg                     #創建項目時自動生成,項目的配置文件
peilv/
    __init__.py                #創建項目時自動生成,無需任何改動
    items.py                   #創建項目時自動生成,定義爬取的字段    
    pipelines.py               #創建項目時自動生成,如存入文件,無需任何改動    
    settings.py                #創建項目時自動生成,將爬取字段按順序輸出    
    middlewares.py             #創建項目時自動生成,無需任何改動    
    spiders/   
        __init__.py            #創建項目時自動生成,無需任何改動	
	itemcsvexporter.py     #需自己編寫,代碼固定	
        爬蟲主程序.py           #需自己編寫,爬蟲的主程序

items.py:

## -*- coding: utf-8 -*-
import scrapy
class PeilvItem(scrapy.Item):
    # define the fields for your item here like:
    cc  = scrapy.Field()#changci
    li =  scrapy.Field()#libo
    b5  = scrapy.Field()#bet365

以上是定義您想抓取的數據,在Scrapy中, 這是通過 Scrapy Items 來完成的。通過scrapy.Field()方法創建需要存儲的字段,比如cc存儲比賽的場次信息,li存儲立博的賠率信息,等等。

關於這個items.py,你只要考慮它就是一個存儲數據的容器,可以考慮成一個結構體,你所有需要提取的信息都在這里面存着。

這里我們需要存儲3個變量,cc,li,b5,所以我在里面加入三個變量,就這么簡單。

pipelines.py:

一般來說,如果你要操作數據庫什么的,需要在這里處理items,你可以把items寫入數據庫,但是今天我們用不到數據庫,scrapy自帶了一個很好的功能就是Feed exports,它支持多種格式的自動輸出。

所以我們直接用這個就好了,pipelines維持不變。

settings.py:

## -*- coding: utf-8 -*-
FEED_EXPORT_ENCODING = "gb18030" #解決導出的 Excel 文件中文亂碼問題
...
FEED_EXPORTERS = {
    'csv': 'peilv.spiders.itemcsvexporter.itemcsvexporter',
}   
FIELDS_TO_EXPORT = [
    'cc',#比賽場次
    'li',#立博的賠率
    'b5',#bet365的賠率
   ]
...

FEED_EXPORT_ENCODING用gb18030常量來解決中文亂碼問題,FEED_EXPORTERS表明了輸出文件的格式,FIELDS_TO_EXPORT給定了輸出字段的順序。

itemcsvexporter.py:

from scrapy.conf import settings
from scrapy.exporters import CsvItemExporter
#指定輸出到 csv 文件中字段的順序,結合 setting.py
class itemcsvexporter(CsvItemExporter):
    def __init__(self, *args, **kwargs):
...

這里需要注意的是有的版本不支持from scrapy.contrib.exporter import CsvItemExporter類,所以用from scrapy.exporters import CsvItemExporter替換即可。
通常結合setting中的字段順序,規定最終CSV文件中的列排序規則。

爬蟲主程序.py:(下一篇詳細介紹)

## -*- coding: utf-8 -*-
ls_url = 'https://live.leisu.com/wanchang?date='#ls歷史https://live.leisu.com/wanchang?date=20190606
class LiveJiangSpider(scrapy.Spider):
    name = 'FBP'
    allowed_domains = ['leisu.com']
    def start_requests(self):
            d1='20190606' #歷史的比賽
            request = scrapy.http.FormRequest(ls_url + d1,callback=self.parseLs, meta={'d1': d1}) #歷史的比賽
            # request = scrapy.http.FormRequest(wl_url + d1,callback=self.parseWl, meta={'d1': d1})#未來的比賽
            yield request
    def parseLs(self,response):
        d2=response.meta['d1']
        sel=response.xpath
        racelist=[e5.split("'") for e5 in sel('//li[@data-status="8"]/@data-id').extract()]
        for raceid in racelist:#raceid=['2674547'];raceid[0]=2674547
            item = PeilvItem()
            sel_div=sel('//li[@data-id='+str(raceid[0])+']/div[@class="find-table layout-grid-tbody hide"]/div[@class="clearfix-row"]')
            if str(sel_div.xpath('span[@class="lab-lottery"]/span[@class="text-jc"]/text()').extract()) == "[]":
                item['cc']=""
            else:
                item['cc']=str(d2) + str(sel_div.xpath('span[@class="lab-lottery"]/span[@class="text-jc"]/text()').extract()[0])
            if "周" in item['cc']:#取競彩-周一001等
                plurl='https://live.leisu.com/3in1-'+raceid[0]
                request = scrapy.http.FormRequest(plurl,callback=self.parse,meta={'item':item})
                yield request #並非return,yield壓隊列,parse函數將會被當做一個生成器使用。scrapy會逐一獲取parse方法中生成的結果,並沒有直接執行parse,循環完成后,再執行parse
    def parse(self, response):
        print('--------------into parse----------------------')
        item = response.meta['item']
        pv=response.xpath
        pl_str = '/td[@class="bd-left"]/div[@class="begin float-left w-bar-100 bd-bottom p-b-8 color-999 m-b-8"]/span[@class="float-left col-3"]/text()'
        if str(pv('//*[@data-id="5"]'+pl_str).extract())=="[]":
            item['li'] =  ''
        else:
            item['li']=pv('//*[@data-id="5"]' + pl_str).extract()[0]
        if str(pv('//*[@data-id="2"]'+pl_str).extract())=="[]":
            item['b5'] =  ''
        else:
            item['b5']=pv('//*[@data-id="2"]' + pl_str).extract()[0]
        yield item#程序在取得各個頁面的items前,會先處理完之前所有的request隊列里的請求,然后再提取items

爬蟲主程序實現了爬取網頁數據的具體邏輯,在下一講會結合一個具體事例詳細介紹。

改寫完程序后,最終執行命令:
Pycharm 用 alt+F12 切換到命令行在項目 peilv 路徑上執行:

(venv2) E:\>cd peilv\peilv 
(venv2) E:\peilv\peilv>scrapy crawl FBP -o BaseData.csv

其中 FBP 是在“爬蟲主程序.py”定義的——name = 'FBP',“-o BaseData.csv” 是將爬取的數據輸出到 csv 文件中。

總結

以上首先創建一個工程和Spider模板,然后編寫Spider,編寫Item Pipeline,借助了Scrapy中的三個類——Request類、Response類和Item類。

同時我們以一個實戰項目為依托,將建立 Scrapy 項目的過程從零開始,深入淺出,讓讀者能夠實踐爬蟲的整個過程。

代碼地址

示例代碼:Python-100-days-day070

關注公眾號:python技術,回復"python"一起學習交流


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM