爬蟲(9) - Scrapy框架(1) | Scrapy 非同步網路爬蟲框架

葛老頭發表於2022-07-05

什麼是Scrapy

  • 基於Twisted的非同步處理框架
  • 純python實現的爬蟲框架
  • 基本結構:5+2框架,5個元件,2箇中介軟體

 

5個元件:

  • Scrapy Engine:引擎,負責其他部件通訊 進行訊號和資料傳遞;負責Scheduler、Downloader、Spiders、Item Pipeline中間的通訊訊號和資料的傳遞,此元件相當於爬蟲的“大腦”,是整個爬蟲的排程中心
  • Scheduler:排程器,將request請求排列入隊,當引擎需要交還給引擎,通過引擎將請求傳遞給Downloader;簡單地說就是一個佇列,負責接收引擎傳送過來的 request請求,然後將請求排隊,當引擎需要請求資料的時候,就將請求佇列中的資料交給引擎。初始的爬取URL和後續在頁面中獲取的待爬取的URL將放入排程器中,等待爬取,同時排程器會自動去除重複的URL(如果特定的URL不需要去重也可以通過設定實現,如post請求的URL)
  • Downloader:下載器,將引擎engine傳送的request進行接收,並將response結果交還給引擎engine,再由引擎傳遞給Spiders處理
  • Spiders:解析器,它負責處理所有responses,從中分析提取資料,獲取Item欄位需要的資料,並將需要跟進的URL提交給引擎,再次進入Scheduler(排程器);同時也是入口URL的地方
  • Item Pipeline:資料管道,就是我們封裝去重類、儲存類的地方,負責處理 Spiders中獲取到的資料並且進行後期的處理,過濾或者儲存等等。當頁面被爬蟲解析所需的資料存入Item後,將被髮送到專案管道(Pipeline),並經過幾個特定的次序處理資料,最後存入本地檔案或存入資料庫

 

2箇中介軟體:

  • Downloader Middlewares:下載中介軟體,可以當做是一個可自定義擴充套件下載功能的元件,是在引擎及下載器之間的特定鉤子(specific hook),處理Downloader傳遞給引擎的response。通過設定下載器中介軟體可以實現爬蟲自動更換user-agent、IP等功能。
  • Spider Middlewares:爬蟲中介軟體,Spider中介軟體是在引擎及Spider之間的特定鉤子(specific hook),處理spider的輸入(response)和輸出(items及requests)。自定義擴充套件、引擎和Spider之間通訊功能的元件,通過插入自定義程式碼來擴充套件Scrapy功能。

 Scrapy操作文件(中文的):https://www.osgeo.cn/scrapy/topics/spider-middleware.html

 

Scrapy框架的安裝

cmd視窗,pip進行安裝

pip install scrapy

Scrapy框架安裝時常見的問題

找不到win32api模組----windows系統中常見

pip install pypiwin32

 

建立Scrapy爬蟲專案

新建專案

scrapy startproject xxx專案名稱

例項:

scrapy startproject tubatu_scrapy_project

 

專案目錄

 

scrapy.cfg:專案的配置檔案,定義了專案配置檔案的路徑等配置資訊

  • 【settings】:定義了專案的配置檔案的路徑,即./tubatu_scrapy_project/settings檔案
  • 【deploy】:部署資訊

 

  • items.py:就是我們定義item資料結構的地方;也就是說我們想要抓取哪些欄位,所有的item定義都可以放到這個檔案中
  • pipelines.py:專案的管道檔案,就是我們說的資料處理管道檔案;用於編寫資料儲存,清洗等邏輯,比如將資料儲存到json檔案,就可以在這邊編寫邏輯
  • settings.py:專案的設定檔案,可以定義專案的全域性設定,比如設定爬蟲的 USER_AGENT ,就可以在這裡設定;常用配置項如下:
    • ROBOTSTXT_OBEY :是否遵循ROBTS協議,一般設定為False
    • CONCURRENT_REQUESTS :併發量,預設是32個併發
    • COOKIES_ENABLED :是否啟用cookies,預設是False
    • DOWNLOAD_DELAY :下載延遲
    • DEFAULT_REQUEST_HEADERS :預設請求頭
    • SPIDER_MIDDLEWARES :是否啟用spider中介軟體
    • DOWNLOADER_MIDDLEWARES :是否啟用downloader中介軟體
    • 其他詳見連結
  • spiders目錄:包含每個爬蟲的實現,我們的解析規則寫在這個目錄下,即爬蟲的解析器寫在這個目錄下
  • middlewares.py:定義了 SpiderMiddleware和DownloaderMiddleware 中介軟體的規則;自定義請求、自定義其他資料處理方式、代理訪問等

 

自動生成spiders模板檔案

cd到spiders目錄下,輸出如下命令,生成爬蟲檔案:

scrapy genspider 檔名 爬取的地址

 

執行爬蟲

方式一:cmd啟動

cd到spiders目錄下,執行如下命令,啟動爬蟲:

scrapy crawl 爬蟲名

 

方式二:py檔案啟動

在專案下建立main.py檔案,建立啟動指令碼,執行main.py啟動檔案,程式碼示例如下:

code-爬蟲檔案?

import scrapy


class TubatuSpider(scrapy.Spider):
    #名稱不能重複
    name = 'tubatu'
    #允許爬蟲去抓取的域名
    allowed_domains = ['xiaoguotu.to8to.com']
    #專案啟動之後要啟動的爬蟲檔案
    start_urls = ['https://xiaoguotu.to8to.com/pic_space1?page=1']

    #預設的解析方法
    def parse(self, response):
        print(response.text)

code-啟動檔案?

from scrapy import cmdline

#在我們scrapy專案裡面,為了方便執行scrapy的專案的時候建立的檔案
#使用cmdlie.execute()方法執行爬蟲啟動命令:scrapy crawl 爬蟲名
cmdline.execute("scrapy crawl tubatu".split())  #execute方法需要執行的每一個命令為單獨的一個字串,如:cmdline.execute(['scrapy', 'crawl', 'tubatu']),所以如果命令為一整個字串時,需要split( )進行分割;#

code-執行結果?

示例專案

爬取土巴兔裝修網站資訊。將爬取到的資料存入到本地MongoDB資料庫中;

下圖?為專案機構,標藍的檔案就是此次code的程式碼

tubatu.py

 1 import scrapy
 2 from tubatu_scrapy_project.items import TubatuScrapyProjectItem
 3 import re
 4 
 5 class TubatuSpider(scrapy.Spider):
 6 
 7     #名稱不能重複
 8     name = 'tubatu'
 9     #允許爬蟲去抓取的域名,超過這個目錄就不允許抓取
10     allowed_domains = ['xiaoguotu.to8to.com','wx.to8to.com','sz.to8to.com']
11     #專案啟動之後要啟動的爬蟲檔案
12     start_urls = ['https://xiaoguotu.to8to.com/pic_space1?page=1']
13 
14 
15     #預設的解析方法
16     def parse(self, response):
17         # response後面可以直接使用xpath方法
18         # response就是一個Html物件
19         pic_item_list = response.xpath("//div[@class='item']")
20         for item in pic_item_list[1:]:
21             info = {}
22             # 這裡有一個點不要丟了,是說明在當前Item下面再次使用xpath
23             # 返回的不僅僅是xpath定位中的text()內容,需要再過濾;返回如:[<Selector xpath='.//div/a/text()' data='0元搞定設計方案,限名額領取'>] <class 'scrapy.selector.unified.SelectorList'>
24             # content_name = item.xpath('.//div/a/text()')
25 
26             #使用extract()方法獲取item返回的data資訊,返回的是列表
27             # content_name = item.xpath('.//div/a/text()').extract()
28 
29             #使用extract_first()方法獲取名稱,資料;返回的是str型別
30             #獲取專案的名稱,專案的資料
31             info['content_name'] = item.xpath(".//a[@target='_blank']/@data-content_title").extract_first()
32 
33             #獲取專案的URL
34             info['content_url'] = "https:"+ item.xpath(".//a[@target='_blank']/@href").extract_first()
35 
36             #專案id
37             content_id_search = re.compile(r"(\d+)\.html")
38             info['content_id'] = str(content_id_search.search(info['content_url']).group(1))
39 
40             #使用yield來傳送非同步請求,使用的是scrapy.Request()方法進行傳送,這個方法可以傳cookie等,可以進到這個方法裡面檢視
41             #回撥函式callback,只寫方法名稱,不要呼叫方法
42             yield scrapy.Request(url=info['content_url'],callback=self.handle_pic_parse,meta=info)
43 
44         if response.xpath("//a[@id='nextpageid']"):
45             now_page = int(response.xpath("//div[@class='pages']/strong/text()").extract_first())
46             next_page_url="https://xiaoguotu.to8to.com/pic_space1?page=%d" %(now_page+1)
47             yield scrapy.Request(url=next_page_url,callback=self.parse)
48 
49 
50     def handle_pic_parse(self,response):
51         tu_batu_info = TubatuScrapyProjectItem()
52         #圖片的地址
53         tu_batu_info["pic_url"]=response.xpath("//div[@class='img_div_tag']/img/@src").extract_first()
54         #暱稱
55         tu_batu_info["nick_name"]=response.xpath("//p/i[@id='nick']/text()").extract_first()
56         #圖片的名稱
57         tu_batu_info["pic_name"]=response.xpath("//div[@class='pic_author']/h1/text()").extract_first()
58         #專案的名稱
59         tu_batu_info["content_name"]=response.request.meta['content_name']
60         # 專案id
61         tu_batu_info["content_id"]=response.request.meta['content_id']
62         #專案的URL
63         tu_batu_info["content_url"]=response.request.meta['content_url']
64         #yield到piplines,我們通過settings.py裡面啟用,如果不啟用,將無法使用
65         yield tu_batu_info

items.py

 1 # Define here the models for your scraped items
 2 #
 3 # See documentation in:
 4 # https://docs.scrapy.org/en/latest/topics/items.html
 5 
 6 import scrapy
 7 
 8 
 9 class TubatuScrapyProjectItem(scrapy.Item):
10     # define the fields for your item here like:
11     # name = scrapy.Field()
12 
13     #裝修名稱
14     content_name=scrapy.Field()
15     #裝修id
16     content_id = scrapy.Field()
17     #請求url
18     content_url=scrapy.Field()
19     #暱稱
20     nick_name=scrapy.Field()
21     #圖片的url
22     pic_url=scrapy.Field()
23     #圖片的名稱
24     pic_name=scrapy.Field()

piplines.py

 1 # Define your item pipelines here
 2 #
 3 # Don't forget to add your pipeline to the ITEM_PIPELINES setting
 4 # See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
 5 
 6 
 7 # useful for handling different item types with a single interface
 8 from itemadapter import ItemAdapter
 9 
10 from pymongo import MongoClient
11 
12 class TubatuScrapyProjectPipeline:
13 
14     def __init__(self):
15         client = MongoClient(host="localhost",
16                              port=27017,
17                              username="admin",
18                              password="123456")
19         mydb=client['db_tubatu']
20         self.mycollection = mydb['collection_tubatu']
21 
22     def process_item(self, item, spider):
23         data = dict(item)
24         self.mycollection.insert_one(data)
25         return item

settings.py

main.py

1 from scrapy import cmdline
2 
3 #在我們scrapy專案裡面,為了方便執行scrapy的專案的時候建立的檔案
4 #使用cmdlie.execute()方法執行爬蟲啟動命令:scrapy crawl 爬蟲名
5 cmdline.execute("scrapy crawl tubatu".split())  #execute方法需要執行的每一個命令為單獨的一個字串,如:cmdline.execute(['scrapy', 'crawl', 'tubatu']),所以如果命令為一整個字串時,需要split( )進行分割;#

 

相關文章