Python Scrapy爬蟲教程-更新

之前我簡單的實現了 Scrapy的基本內容。
存在兩個問題需要解決。

  • 先爬取詳情頁面,在根據頁面url獲取圖片太費事了,要進行簡化,一個項目就實現圖片爬取。
  • 增量爬蟲,網站數據更新,獲取更新內容。

一般爬蟲的邏輯是:給定起始頁面,發起訪問,分析頁面包含的所有其他鏈接,然後將這些鏈接放入隊列,再逐次訪問這些隊列,直至邊界條件結束。爲了針對列表頁+詳情頁這種模式,需要對鏈接抽取(link extractor)的邏輯進行限定。我們先了解一下 crawlspider rules。

crawlspider rules的運行機制

request url的獲取是Rule定位到的容器裏,所有a標籤裏的href鏈接,比如用xpath定位。

rules = (
        Rule(LinkExtractor(restrict_xpaths=("//table[@class="tbspan"]/tr/td/b/a[2]")),callback='parse_item'),
    )

LinkExtractor 構造器各參數說明:https://www.cnblogs.com/xinglejun/p/10408630.html

容器下的所有a標籤的鏈接全都會被獲取到,並且侍自動發送請求,不用自己手動發送請求。響應頁面是Rule請求的鏈接的頁面內容,也就是你定位容器ul裏的a標籤的鏈接,然後你用鼠標點擊該鏈接所看到的頁面內容,在callback函數裏提取數據也是在這個頁面裏提取,parse_item(self,response),這個函數的response對象就是這個頁面內容,千萬不要搞錯對象了。

follow,follow就是跟進的意思,如果follow=True,那麼,在你獲取到的響應頁面裏,所以符合Rule規則的href鏈接都會被獲取到,而且它還會自動跟進,進入到獲取到的鏈接響應頁面,在該頁面又一次匹配Rule規則,看看有沒有符合的,如果有又繼續跟進,一直到匹配不到規則爲止。
詳細的解釋看:https://blog.csdn.net/joe8910/article/details/85159059。

rules = (
         Rule(LinkExtractor(restrict_xpaths=("//table[@class="tbspan"]/tr/td/b/a[2]")),callback='parse_item'),
         Rule(LinkExtractor(allow=r'list_4_\d+\.html'), callback='parse_item', follow=True),
)

一條是獲取響應頁面規則,一條是獲取翻頁鏈接規則。我們運行一下試試。

class ChinesemedicineSpider(CrawlSpider):
    name = 'chinesemedicine'
    #allowed_domains = ['http://yzs.satcm.gov.cn']
    start_urls = ['https://www.ygdy8.net/html/gndy/china/index.html']

    rules = (
        Rule(LinkExtractor(restrict_xpaths=("//table[@class='tbspan']/tr/td/b/a[2]")),callback='parse_item'),
        Rule(LinkExtractor(allow=r'list_4_\d+\.html'), follow=True),
    )
    def parse_item(self, response):
        item = {}
        print('page: %s' % response.url)

在這裏插入圖片描述
這個是一個方法實現,但我們不選擇這個,而選擇另一個辦法實現。

class ChinesemedicineSpider(CrawlSpider):
    name = 'chinesemedicine'
    #allowed_domains = ['http://yzs.satcm.gov.cn']
    start_urls = ['https://www.ygdy8.net/html/gndy/china/index.html']

    rules = (
        Rule(LinkExtractor(allow=r'list_4_\d+\.html'),callback='parse_item', follow=True),
    )
    def parse_item(self, response):
           detail_url_list = ['https://www.ygdy8.net' + el for el in  response.xpath( "//table[@class='tbspan']/tr/td/b/a[2]/@href").extract()]        
        for url in detail_url_list:
            yield scrapy.Request(url=url, callback=self.parse_detail)

    def parse_detail(self,response):
        print('url :'+response.xpath('//p/img[1]/@src').extract_first())

他與上一個類似,但區別在於使用 parse_detail(self,response)來解析詳情頁面,這個好處在於我們後面在增量查詢時,減少建立連接數。

增量式爬取工作

  • 在發送請求之前判斷這個URL之前是不是爬取過
  • 在解析內容之後判斷該內容之前是否爬取過
  • 在寫入存儲介質時判斷內容是不是在該介質中

去重的方法
將爬取過程中產生的URL進行存儲,存入到redis中的set中,當下次再爬取的時候,對在存儲的URL中的set中進行判斷,如果URL存在則不發起請求,否則就發起請求。
對爬取到的網站內容進行唯一的標識,然後將該唯一標識存儲到redis的set中,當下次再爬取數據的時候,在進行持久化存儲之前,要判斷該數據的唯一標識在不在redis中的set中,如果在,則不在進行存儲,否則就存儲該內容。
一般而言,對url的去重是增量爬蟲的關鍵,所以必須去重。爬蟲爬取的是大規模的相同類型網站,對於每一個爬蟲的結果還會彙總,所以對於內容解析去重並不一定要做,我們可以在彙總後寫入存儲介質時再去重,但對於彙總時對傳輸有要求時,還是解析內容去重。

Redis 安裝

Window 下安裝
下載地址:https://github.com/tporadowski/redis/releases。

Redis 支持 32 位和 64 位。這個需要根據你係統平臺的實際情況選擇,這裏我們下載 Redis-x64-xxx.zip壓縮包到 C 盤,解壓後,將文件夾重新命名爲 redis。
打開一個 cmd 窗口 使用 cd 命令切換目錄到 C:\redis 運行:

redis-server.exe redis.windows.conf

如果想方便的話,可以把 redis 的路徑加到系統的環境變量裏,這樣就省得再輸路徑了,後面的那個 redis.windows.conf 可以省略,如果省略,會啓用默認的。

這時候另啓一個 cmd 窗口,原來的不要關閉,不然就無法訪問服務端了。

切換到 redis 目錄下運行:

redis-cli.exe -h 127.0.0.1 -p 6379

這樣就可以在shell中操作redis了。

Redis 的 Set 是 String 類型的無序集合。集合成員是唯一的,這就意味着集合中不能出現重複的數據。

Redis 中集合是通過哈希表實現的,所以添加,刪除,查找的複雜度都是 O(1)。
我們把爬取過的url添加到Redis的set中,這樣就可以通過判斷url是否在set中判斷url是否爬取過。
具體代碼如下:

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from redis import Redis

class ChinesemedicineSpider(CrawlSpider):
    name = 'chinesemedicine'
    start_urls = ['https://www.ygdy8.net/html/gndy/china/index.html']

    rules = (
        Rule(LinkExtractor(allow=r'list_4_\d+\.html'),callback='parse_item', follow=True),
    )
    def parse_item(self, response):
        conn = Redis(host='127.0.0.1', port=6379)
        detail_url_list = ['https://www.ygdy8.net' + el for el in  response.xpath(
            "//table[@class='tbspan']/tr/td/b/a[2]/@href").extract()]
        
        for url in detail_url_list:
            # ex == 1:set中沒有存儲url
            print("from :"+ url)
            ex = conn.sadd('movies_url',url)
            if ex == 1:
                yield scrapy.Request(url=url, callback=self.parse_detail)
            else:
                print('已爬取過')

    def parse_detail(self,response):
        #item = Scrapy2Item()
        print('url :'+response.xpath('//p/img[1]/@src').extract_first())
        #yield item

這樣我們實現了簡單的增量爬蟲。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章