關閉

                  增量式爬蟲,到底是個啥

                  發表于:2021-10-21 09:27

                  字體: | 上一篇 | 下一篇 | 我要投稿

                   作者:波曉張    來源:博客園

                  #
                  爬蟲
                    引言:
                    當我們在瀏覽相關網頁的時候會發現,某些網站定時會在原有網頁數據的基礎上更新一批數據,例如某電影網站會實時更新一批最近熱門的電影。小說網站會根據作者創作的進度實時更新最新的章節數據等等。那么,類似的情景,當我們在爬蟲的過程中遇到時,我們是不是需要定時更新程序以便能爬取到網站中最近更新的數據呢?

                    一.增量式爬蟲
                    概念:通過爬蟲程序監測某網站數據更新的情況,以便可以爬取到該網站更新出的新數據。
                    如何進行增量式的爬取工作:
                    · 在發送請求之前判斷這個URL是不是之前爬取過
                    · 在解析內容后判斷這部分內容是不是之前爬取過
                    · 寫入存儲介質時判斷內容是不是已經在介質中存在
                    分析:
                    不難發現,其實增量爬取的核心是去重, 至于去重的操作在哪個步驟起作用,只能說各有利弊。在我看來,前兩種思路需要根據實際情況取一個(也可能都用)。第一種思路適合不斷有新頁面出現的網站,比如說小說的新章節,每天的最新新聞等等;第二種思路則適合頁面內容會更新的網站。第三個思路是相當于是最后的一道防線。這樣做可以最大程度上達到去重的目的。
                    去重方法
                    將爬取過程中產生的url進行存儲,存儲在redis的set中。當下次進行數據爬取時,首先對即將要發起的請求對應的url在存儲的url的set中做判斷,如果存在則不進行請求,否則才進行請求。
                    對爬取到的網頁內容進行唯一標識的制定,然后將該唯一表示存儲至redis的set中。當下次爬取到網頁數據的時候,在進行持久化存儲之前,首先可以先判斷該數據的唯一標識在redis的set中是否存在,在決定是否進行持久化存儲。

                    二.項目案例
                    - 需求:爬取4567tv網站中所有的電影詳情數據。
                    爬蟲文件:
                  # -*- coding: utf-8 -*-
                  import scrapy
                  from scrapy.linkextractors import LinkExtractor
                  from scrapy.spiders import CrawlSpider, Rule

                  from redis import Redis
                  from incrementPro.items import IncrementproItem
                  class MovieSpider(CrawlSpider):
                      name = 'movie'
                      # allowed_domains = ['www.xxx.com']
                      start_urls = ['http://www.4567tv.tv/frim/index7-11.html']

                      rules = (
                          Rule(LinkExtractor(allow=r'/frim/index7-\d+\.html'), callback='parse_item', follow=True),
                      )
                      #創建redis鏈接對象
                      conn = Redis(host='127.0.0.1',port=6379)
                      def parse_item(self, response):
                          li_list = response.xpath('//li[@class="p1 m1"]')
                          for li in li_list:
                              #獲取詳情頁的url
                              detail_url = 'http://www.4567tv.tv'+li.xpath('./a/@href').extract_first()
                              #將詳情頁的url存入redis的set中
                              ex = self.conn.sadd('urls',detail_url)
                              if ex == 1:
                                  print('該url沒有被爬取過,可以進行數據的爬取')
                                  yield scrapy.Request(url=detail_url,callback=self.parst_detail)
                              else:
                                  print('數據還沒有更新,暫無新數據可爬!')

                      #解析詳情頁中的電影名稱和類型,進行持久化存儲
                      def parst_detail(self,response):
                          item = IncrementproItem()
                          item['name'] = response.xpath('//dt[@class="name"]/text()').extract_first()
                          item['kind'] = response.xpath('//div[@class="ct-c"]/dl/dt[4]//text()').extract()
                          item['kind'] = ''.join(item['kind'])
                          yield item

                    管道文件:
                  # -*- coding: utf-8 -*-

                  # Define your item pipelines here
                  #
                  # Don't forget to add your pipeline to the ITEM_PIPELINES setting
                  # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html

                  from redis import Redis
                  class IncrementproPipeline(object):
                      conn = None
                      def open_spider(self,spider):
                          self.conn = Redis(host='127.0.0.1',port=6379)
                      def process_item(self, item, spider):
                          dic = {
                              'name':item['name'],
                              'kind':item['kind']
                          }
                          print(dic)
                          self.conn.lpush('movieData',dic)
                          return item

                    - 需求:爬取糗事百科中的段子和作者數據。
                    爬蟲文件:
                  # -*- coding: utf-8 -*-
                  import scrapy
                  from scrapy.linkextractors import LinkExtractor
                  from scrapy.spiders import CrawlSpider, Rule
                  from incrementByDataPro.items import IncrementbydataproItem
                  from redis import Redis
                  import hashlib
                  class QiubaiSpider(CrawlSpider):
                      name = 'qiubai'
                      # allowed_domains = ['www.xxx.com']
                      start_urls = ['https://www.qiushibaike.com/text/']

                      rules = (
                          Rule(LinkExtractor(allow=r'/text/page/\d+/'), callback='parse_item', follow=True),
                          Rule(LinkExtractor(allow=r'/text/$'), callback='parse_item', follow=True),
                      )
                      #創建redis鏈接對象
                      conn = Redis(host='127.0.0.1',port=6379)
                      def parse_item(self, response):
                          div_list = response.xpath('//div[@id="content-left"]/div')

                          for div in div_list:
                              item = IncrementbydataproItem()
                              item['author'] = div.xpath('./div[1]/a[2]/h2/text() | ./div[1]/span[2]/h2/text()').extract_first()
                              item['content'] = div.xpath('.//div[@class="content"]/span/text()').extract_first()

                              #將解析到的數據值生成一個唯一的標識進行redis存儲
                              source = item['author']+item['content']
                              source_id = hashlib.sha256(source.encode()).hexdigest()
                              #將解析內容的唯一表示存儲到redis的data_id中
                              ex = self.conn.sadd('data_id',source_id)

                              if ex == 1:
                                  print('該條數據沒有爬取過,可以爬取......')
                                  yield item
                              else:
                                  print('該條數據已經爬取過了,不需要再次爬取了!!!')

                    管道文件:
                  # -*- coding: utf-8 -*-

                  # Define your item pipelines here
                  #
                  # Don't forget to add your pipeline to the ITEM_PIPELINES setting
                  # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html

                  from redis import Redis
                  class IncrementbydataproPipeline(object):
                      conn = None

                      def open_spider(self, spider):
                          self.conn = Redis(host='127.0.0.1', port=6379)

                      def process_item(self, item, spider):
                          dic = {
                              'author': item['author'],
                              'content': item['content']
                          }
                          # print(dic)
                          self.conn.lpush('qiubaiData', dic)
                          return item

                    本文內容不用于商業目的,如涉及知識產權問題,請權利人聯系51Testing小編(021-64471599-8017),我們將立即處理
                  《2023軟件測試行業現狀調查報告》獨家發布~

                  關注51Testing

                  聯系我們

                  快捷面板 站點地圖 聯系我們 廣告服務 關于我們 站長統計 發展歷程

                  法律顧問:上海蘭迪律師事務所 項棋律師
                  版權所有 上海博為峰軟件技術股份有限公司 Copyright©51testing.com 2003-2024
                  投訴及意見反饋:webmaster@51testing.com; 業務聯系:service@51testing.com 021-64471599-8017

                  滬ICP備05003035號

                  滬公網安備 31010102002173號

                  亚洲欧洲自拍图片专区123_久久久精品人妻无码专区不卡_青青精品视频国产色天使_A免看的日黄亚洲