scrapy基本操作流程


基本配置與命令

1.安裝

win系統下有5個步驟

         pip3 install wheel
         twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
         pip3 install Twisted 17.1.0 cp35 cp35m win_amd64.wheel
         pip install pywin32
         pip install scrapy

2.創建

       scrapy startproject 項目名

         - 創建普通爬蟲文件

        cd 項目名 (進入項目目錄之后再創建爬蟲文件)
        scrapy genspider 爬蟲文件名 www.xxx.com   

         - 創建crawlspider的爬蟲文件

        scrapy genspider -t crawl 爬蟲文件名 www.xxx.com

         - 一般注釋掉 allowed_domains = ['www.xxx.com']

3.配置項目

   ROBOTSTXT_OBEY = False 不遵守機器人規則
   USER_AGENT = '' 配置UA
   LOG_LEVEL = 'ERROR'  配置日志級別

         中間件配置,管道配置時將注釋取消即可  

4.執行項目

   scrapy crawl 爬蟲文件名
   scrapy crawl 爬蟲文件名 --nolog 不顯示日志運行
   scrapy crawl 爬蟲文件名 -o 文件名.csv/json 保存結果到文件

應用

1.持久化本地存儲

         1.使用命令,保存的本地文件格式限制為 (json csv xml jl jsonlines marshal pickle)

        scrapy crawl 爬蟲文件名 -o 本地文件名.csv 

         2.使用管道

                  - 在settings.py中開啟管道!!!

                  - items.py文件中添加字段,如  name = scrapy.Field() 

                  - 注意在爬蟲文件中要yield item 管道類中才能接受到item

                  - 在piplines.py文件中的管道類中的process_item函數中處理

                          - 爬蟲類

        •  open_spider()
        •  close_spider()
        •  process_item()

2.爬取全部網站的數據

         手動請求發送,在爬蟲文件中的parse中,(callback是回調另一個parse解析函數)

       yield scrapy.Request(url,callback)

3.進行post請求發送

         spider類中重寫start_requests(self)方法,yield scrapy.FormRequest(url,parse,formdata)

       def start_requestS(self):
           for url in self.start_urls:
               data = { 'kw':'cat'}
               yield scrapy.FormRequest(url=url,callback=self.parse,formdata=data)

4.處理cookie

         - scrapy默認情況下自動處理cookie,在settings.py中配置  

          COOKIES_ENABLED = False

5.請求傳參

  - 使用場景:如果使用scrapy爬取的數據沒有在同一張頁面中,則必須使用請求傳參

  - 編碼流程:

  - 需求:爬取的是 首頁中電影的名稱和 詳情頁中電影的簡介(全站數據爬取)

  - 基於起始url進行數據解析(parse)

    - 解析數據

      • 電影的名稱
      • 詳情頁的url
      • 對詳情頁的url發起手動請求(指定的回調函數parse_detail),進行請求傳參(meta)meta傳遞給parse_detail這個回調函數

               - 封裝一個其他頁碼對應url的一個通用的URL模板

               - 在for循環外部,手動對其他頁的url進行手動請求發送(需要指定回調函數==》parse)

               - 定義parse_detail回調方法,在其內部對電影的簡介進行解析。解析完畢后,需要將解析到的電影名稱和電影的簡介封裝到同一個item中。

               - 接收傳遞過來的item,並且將解析到的數據存儲到item中,將item提交給管道 

         def parse_news(self,response):
                  item = WangyiproItem()
                  item['title'] = title
                  yield scrapy.Request(url=news_detail_url,callback=self.parse_detail,meta={'item':item})
              
         def parse_detail(self,response):
                  item = response.meta['item']
                  item['content'] = content
                  yield item

5.中間件

         - 在settings中要取消注釋才能生效

         - DOWNLOADER_MIDDLEWARES 下載中間件: 批量攔截所有的請求和響應

         - process_request 攔截請求

    1.  用來進行UA偽裝,結合UA列表使用
    2.  使用代理ip,結合ip池使用

         - process_response 攔截相應

                  可以在爬取動態加載的頁面時結合selenium使用

         from scrapy import signals

         import random

 

         #批量攔截所有的請求和響應

         class MiddlewearproDownloaderMiddleware(object):

                  #UA池

                  user_agent_list = [

                          "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 "

                          "(KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",

                          "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 "

                          "(KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",

                          "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 "

                          "(KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",

                          "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 "

                          "(KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",

                          "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 "

                          "(KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",

                          "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 "

                          "(KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",

                          "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 "

                          "(KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",

                          "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "

                          "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",

                          "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 "

                          "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",

                          "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 "

                          "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",

                          "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "

                          "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",

                          "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "

                          "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",

                          "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "

                          "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",

                          "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "

                          "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",

                          "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 "

                          "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",

                          "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "

                          "(KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",

                          "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 "

                          "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",

                          "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 "

                          "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"

                  ]

                  #代理池

                  PROXY_http = [

                          '153.180.102.104:80',

                          '195.208.131.189:56055',

                  ]

                  PROXY_https = [

                          '120.83.49.90:9000',

                          '95.189.112.214:35508',

                  ]

 

                  #攔截正常請求:request就是該方法攔截到的請求,spider就是爬蟲類實例化的一個對象

                  def process_request(self, request, spider):

                          print('this is process_request!!!')

                          #UA偽裝

                          request.headers['User-Agent'] = random.choice(self.user_agent_list)

                          return None

 

                  #攔截所有的響應

                  def process_response(self, request, response, spider):

 

                          return response

 

                  #攔截發生異常的請求對象

                  def process_exception(self, request, exception, spider):

                          print('this is process_exception!!!!')

                          #代理ip的設定

                          if request.url.split(':')[0] == 'http':

                                   request.meta['proxy'] = random.choice(self.PROXY_http)

                          else:

                                   request.meta['proxy'] = random.choice(self.PROXY_https)

 

                          #將修正后的請求對象重新進行請求發送

                          return request
View Code

6.scrapy中使用selenium

         1.spider類中定義一個屬性 (類屬性)

         browser = Chrome(executable_path='chromedriver.exe')

         2.spider類中重寫一個方法closed, 在該方法中關閉browser

         def closed(self,spider):
             self.browser.quit()

         3.在中間件類的process_response中編寫selenium自動化的相關操作

                 class DownloaderMiddleware(object):

                          #攔截整個工程中所有的響應對象

                          def process_response(self, request, response, spider):

                                   if request.url in spider.urls:

                                            #獲取了在爬蟲類中定義好的瀏覽器對象

                                            bro = spider.bro

                                            bro.get(request.url)

 

                                            bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')

                                            sleep(1)

 

                                            #獲取攜帶了新聞數據的頁面源碼數據

                                            page_text = bro.page_source

                                            #實例化一個新的響應對象

                                            new_response = HtmlResponse(url=request.url,body=page_text,encoding='utf-8',request=request)

                                            return new_response

                                   else:

                                            return response
View Code

7.CrawlSpider 自動爬取全站的數據

         - 作用:就是用於進行全站數據的爬取

         - 新建一個CrawlSpider類的爬蟲文件       

         scrapy genspider -t crawl xxx www.xxx.com

         - LinkExtractor 連接提取器:根據指定規則(正則表達式)進行連接的提取

         - Rule規則解析器:

                  將鏈接提取器提取到的鏈接進行請求發送,然后對獲取的頁面數據進行指定規則的解析(callback)

         一個連接提取器對應唯一一個規則解析器

        

         - 示例 使用CrawlSpider爬取陽光問政王標題及詳情頁內容

                  # -*- coding: utf-8 -*-

                  import scrapy

                  from scrapy.linkextractors import LinkExtractor

                  from scrapy.spiders import CrawlSpider, Rule

 

                  from sunLinePro.items import SunlineproItem,ContentItem

                  class SunSpider(CrawlSpider):

                          name = 'sun'

                          # allowed_domains = ['www.xxx.com']

                          start_urls = ['http://wz.sun0769.com/index.php/question/questionType?type=4&page=']

 

                          link= LinkExtractor(allow=r'type=4&page=\d+')#提取頁碼連接

 

                          link1 = LinkExtractor(allow=r'question/2019\d+/\d+\.shtml')#提取詳情頁的鏈接

                          rules = (

                                   Rule(link, callback='parse_item', follow=False),

                                   Rule(link1, callback='parse_detail'),

                          )

                          #解析出標題和網友名稱

                          def parse_item(self, response):

                                   tr_list = response.xpath('//*[@id="morelist"]/div/table[2]//tr/td/table//tr')

                                   for tr in tr_list:

                                            title = tr.xpath('./td[2]/a[2]/text()').extract_first()

                                            netFriend = tr.xpath('./td[4]/text()').extract_first()

                                            item = SunlineproItem()

                                            item['title'] = title

                                            item['netFriend'] = netFriend

 

                                            yield item

                          #解析出新聞的內容

                          def parse_detail(self,response):

                                   content = response.xpath('/html/body/div[9]/table[2]//tr[1]/td/div[2]//text()').extract()

                                   content = ''.join(content)

 

                                   item = ContentItem()

                                   item['content'] = content

 

                                   yield item
View Code

 

scrapy分布式爬蟲

1.概念:

         可以將一組程序執行在多台機器上(分布式機群),使其進行數據的分布爬取。

2.原生的scrapy框架是否可以實現分布式?不可以.

         - 調度器不可以被分布式機群共享

         - 管道不可以被分布式機群共享

3.借助scrapy-redis這個模塊幫助scrapy實現分布式

         - scrapy-redis作用:

         - 可以提供可以被共享的管道和調度器

        

4.使用scrapy-redis:

         1.安裝scrapy-redis:

       pip install scrapy-redis

         2.爬蟲文件中:

                  - spider對應的分布式類

           from scrapy_redis.spiders import RedisSpider 

                  - Crawlspider對應的分布式類

          from scrapy_redis.spiders import RedisCrawlSpider          

         3.修改爬蟲文件的代碼:

                  - 將當前爬蟲類的父類從CrawlSpider修改成RedisCrawlSpider

                  - 將start_urls刪除

                  - 添加一個新的類屬性redis_key = 'ts' (可以被共享的調度器中的隊列名稱)

         4.設置管道piplines.py

    ITEM_PIPELINES = {
           'scrapy_redis_ep.pipelines.RedisPipeline': 400
           # 'scrapyRedisPro.pipelines.ScrapyredisproPipeline': 300, }

         5.settings.py中設置調度器

      # 使用scrapy-redis組件的去重隊列,增加了一個去重容器類的配置, 作用使用Redis的set集合來存儲請求的指紋數據, 從而實現請求去重的持久化
      DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 使用scrapy-redis組件的調度器 SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 是否暫停,配置調度器是否要持久化, 也就是當爬蟲結束了, 要不要清空Redis中請求隊列和去重指紋的set。如果是True, 就表示要持久化存儲, 就不清空數據, 否則清空數據 SCHEDULER_PERSIST = True

         6.settings.py中設置redis服務器  

      REDIS_HOST = '192.168.12.154'
      REDIS_PORT = 6379
      # REDIS_ENCODING = 'utf-8'
      # REDIS_PARAMS = {'password':'123456'}

         7.配置redis:

                  修改Redis的配置文件:redis.windows.conf

        - #bind 127.0.0.1
        - protected-mode no        

         8.啟動redis

                  攜帶配置文件啟動redis服務                  

          redis-server ./redis.windows.conf       

                  啟動redis客戶端                     

        redis-cli         

                  執行工程

                           scrapy runspider xxx.py 

                  手動將起始url扔入調度器的隊列中,在redis客戶端中輸入命令(redis-cli), xxx.com為起始url

                           lpush ts www.xxx.com 

                  查看爬取的所有items

                          lrange 爬蟲文件名:items 0 -1 

增量式爬蟲

增量式爬蟲

         - 概念:監測網上數據更新的情況

                  比如爬取電影網時,過一段時間又會有新的電影產生,這是就不能再將所有數據存儲到數據庫中了因為會重復

         - 數據指紋

                  將爬取的數據進行hash等方式轉換為一個不重復的值,存到數據庫中.

                  比如爬取糗百時,將爬到的標題和段子內容原始數據第一步先持久化存儲,第二步再將標題和內容拼接成一個字符串再進行hash生成一個data_id存入數據庫, 在下一次爬取時就可以將標題和內容拼接生成hash值(data_id),在數據庫中查詢是否存在這個id值,進而判斷數據是否存在                       

import scrapy
    from scrapy.linkextractors import LinkExtractor
    from scrapy.spiders import CrawlSpider, Rule
    from redis import Redis
    from moviePro.items import MovieproItem
    class MovieSpider(CrawlSpider):
        name = 'movie'
        # allowed_domains = ['www.xxx.com']
        start_urls = ['https://www.4567tv.tv/frim/index1.html']
        link = LinkExtractor(allow=r'/frim/index1-\d+.html')
        rules = (
            Rule(link, callback='parse_item', follow=False),
        )
        conn = Redis(host='127.0.0.1',port=6379)
        #解析電影的名稱和詳情頁的url
        def parse_item(self, response):
            li_list = response.xpath('/html/body/div[1]/div/div/div/div[2]/ul/li')
            for li in li_list:
                title = li.xpath('./div/a/@title').extract_first()
                detail_url = 'https://www.4567tv.tv'+li.xpath('./div/a/@href').extract_first()
                item = MovieproItem()
                item['title'] = title

                #判斷該詳情頁的url是否進行請求發送
                ex = self.conn.sadd('movie_detail_urls',detail_url)

                if ex == 1:#說明detail_url不存在於redis的set中
                    print('已有最新數據更新,請爬......')
                    yield scrapy.Request(url=detail_url,callback=self.parse_detail,meta={'item':item})
                else:
                    print('暫無新數據的更新!!!')

        def parse_detail(self,response):
            item = response.meta['item']
            desc = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[5]/span[2]/text()').extract_first()
            item['desc'] = desc

            yield item
View Code

         管道文件:

class MovieproPipeline(object):
            def process_item(self, item, spider):
                dic = {
                    'title':item['title'],
                    'desc':item['desc']
                }
                conn = spider.conn

                conn.lpush('movie_data',dic)
                return item
View Code

 

        

 


免責聲明!

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



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