什麼是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( )進行分割;#