爬蟲:scrapy之【請求傳參(item) + 發送post、get請求 + 日志等級 + 中間件 + selenium】


scrapy之遞歸解析(爬取多頁頁面數據)

1.遞歸爬取解析多頁頁面數據

  - 需求:將糗事百科所有頁碼的作者和段子內容數據進行爬取切持久化存儲

  - 需求分析:每一個頁面對應一個url,則scrapy工程需要對每一個頁碼對應的url依次發起請求,然后通過對應的解析方法進行作者和段子內容的解析。

實現方案:

     1.將每一個頁碼對應的url存放到爬蟲文件的起始url列表(start_urls)中。(不推薦)

     2.使用Request方法手動發起請求。(推薦)

# -*- coding: utf-8 -*-
import scrapy
from qiushibaike.items import QiushibaikeItem
# scrapy.http import Request
class QiushiSpider(scrapy.Spider):
    name = 'qiushi'
    allowed_domains = ['www.qiushibaike.com']
    start_urls = ['https://www.qiushibaike.com/text/']

    #爬取多頁
    pageNum = 1 #起始頁碼
    url = 'https://www.qiushibaike.com/text/page/%s/' #每頁的url

    def parse(self, response):
        div_list=response.xpath('//*[@id="content-left"]/div')
        for div in div_list:
            #//*[@id="qiushi_tag_120996995"]/div[1]/a[2]/h2
            author=div.xpath('.//div[@class="author clearfix"]//h2/text()').extract_first()
            author=author.strip('\n')
            content=div.xpath('.//div[@class="content"]/span/text()').extract_first()
            content=content.strip('\n')
            item=QiushibaikeItem()
            item['author']=author
            item['content']=content

            yield item #提交item到管道進行持久化

         #爬取所有頁碼數據
        if self.pageNum <= 13: #一共爬取13頁(共13頁)
            self.pageNum += 1 url = format(self.url % self.pageNum) #遞歸爬取數據:callback參數的值為回調函數(將url請求后,得到的相應數據繼續進行parse解析),遞歸調用parse函數
            yield scrapy.Request(url=url,callback=self.parse)    #發送的是get請求,多頁面解析過程一樣,所以回調函數是parse()

scrapy之主動發送請求(get、post)(item傳參數)

scrapy.Request()  發送的是get請求

scrapy.FormRequest()  發送的是post請求

示例1:爬取某電影網站中電影名稱和電影詳情頁中的導演信息(發送get請求,傳item參數,封裝到item對象中)

- move.py

# -*- coding: utf-8 -*-
import scrapy
from moviePro.items import MovieproItem

class MovieSpider(scrapy.Spider):
    name = 'movie'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['https://www.4567tv.tv/frim/index1.html']
    #解析詳情頁中的數據
    def parse_detail(self,response):
        #response.meta返回接收到的meta字典
        item = response.meta['item']
        actor = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[3]/a/text()').extract_first()
        item['actor'] = actor

        yield item

    def parse(self, response):
        li_list = response.xpath('//li[@class="col-md-6 col-sm-4 col-xs-3"]')
        for li in li_list:
            item = MovieproItem()
            name = li.xpath('./div/a/@title').extract_first()
            detail_url = 'https://www.4567tv.tv'+li.xpath('./div/a/@href').extract_first()
            item['name'] = name
            #meta參數:請求傳參.meta字典就會傳遞給回調函數的response參數
            yield scrapy.Request(url=detail_url,callback=self.parse_detail,meta={'item':item})

 

- items.py

import scrapy


class MoveproItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    title = scrapy.Field()
    actor = scrapy.Field() 

 - settings.py

USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'


# Obey robots.txt rules
ROBOTSTXT_OBEY = False

 

示例2:百度翻譯中翻譯“dog”,發送的是post請求(重寫 start_requests() 方法)

# -*- coding: utf-8 -*-
import scrapy

class PostSpider(scrapy.Spider):
    name = 'post'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['https://fanyi.baidu.com/sug']

    def start_requests(self):   # 重寫該方法,發送的是post請求,scrapy.FormRequest()
        data = {
            'kw':'dog'
        }
        for url in self.start_urls:
            # yield scrapy.Request(url=url,callback=self.parse)  #本來該函數封裝的是對url的get請求,scrapy.Request()
            yield scrapy.FormRequest(url=url,callback=self.parse,formdata=data)    #這里重寫,

    def parse(self, response):
        print(response.text)

 

備注:

  1、parse(self,response) 中的response,默認是start_urls中 get 請求后,返回的對象

  2、要發送post請求,需要重寫start_requests(self)方法,使用 scrapy.FormRequest()

  3、get請求,scrapy.Request()

scrapy之日志等級

  - 在使用scrapy crawl spiderFileName運行程序時,在終端里打印輸出的就是scrapy的日志信息。

  - 日志信息的種類:

        ERROR : 一般錯誤

        WARNING : 警告

        INFO : 一般的信息

        DEBUG : 調試信息

       

  - 設置日志信息指定輸出:

    在settings.py配置文件中,加入

                    LOG_LEVEL = ‘指定日志信息種類’即可。

                    LOG_FILE = 'log.txt'則表示將日志信息寫入到指定文件中進行存儲

- settings.py

LOG_LEVEL = "ERROR"      #添加之后,只有出錯的時候才會打印錯誤信息

 

scrapy之中間件  !!!

!!!!  中間件的使用一定要在settings.py中添加類,不然無法執行。

一.下載中間件

先祭出框架圖:

解釋如下:

  - 引擎(Scrapy)

    用來處理整個系統的數據流處理,觸發事務(框架核心)

  - 調度器(Scheduler)

    用來接收引擎發過來的請求,壓入隊列中,並在引擎再次請求的時候返回,可以想象成一個URL(抓取網頁的網址或者說是鏈接)的優先隊列,由它來決定下一個要抓取的網址是什么,同時去除重復的網址

  - 下載器(Downloader)

    用於下載網頁內容,並將網頁內容返回給蜘蛛(Scrapy下載器是建立在twisted這個高效的異步模型上的)

  - 爬蟲(Spiders)

    爬蟲是主要干活的,用於從特定的網頁中提取自己需要的信息,即所謂的實體(Item)。用戶也可以從中提取出鏈接,讓scrapy繼續抓取下一個頁面

  - 項目管道(Pipeline)

    負責處理爬蟲從網頁中抽取的實體,主要的功能是持久化實體,驗證實體的有效性,清除不需要的信息。當頁面被爬蟲解析后,將被發送到項目管道,並經過幾個特定的次序處理數據

 

下載中間件(Downloader Middlewares) 位於scrapy引擎和下載器之間的一層組件。

- 作用:

(1)引擎將請求傳遞給下載器過程中, 下載中間件可以對請求進行一系列處理。比如設置請求的 User-Agent,設置代理等

(2)在下載器完成將Response傳遞給引擎中,下載中間件可以對響應進行一系列處理。比如進行gzip解壓等。

我們主要使用下載中間件處理請求,一般會對請求設置隨機的User-Agent ,設置隨機的代理。目的在於防止爬取網站的反爬蟲策略。

二、UA池(User-Agent)和代理池(使用中間件實現)

參考

1、UA池:User-Agent池

- 作用:盡可能多的將scrapy工程中的請求偽裝成不同類型的瀏覽器身份。

- 操作流程:

    1.在下載中間件中攔截請求

    2.將攔截到的請求的請求頭信息中的UA進行篡改偽裝

    3.在配置文件中開啟下載中間件

2、代理池

- 作用:盡可能多的將scrapy工程中的請求的IP設置成不同的。

- 操作流程:

    1.在下載中間件中攔截請求

    2.將攔截到的請求的IP修改成某一代理IP

    3.在配置文件中開啟下載中間件

# middles.py

import random


# 中間件要寫在下載中間件中
class MiddleproDownloaderMiddleware(object):
    # Not all methods need to be defined. If a method is not defined,
    # scrapy acts as if the downloader middleware does not modify the
    # passed objects.

    @classmethod
    def from_crawler(cls, crawler):
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    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"
    ]
    # 可被選用的代理IP
    PROXY_http = [
        '153.180.102.104:80',
        '195.208.131.189:56055',
    ]
    PROXY_https = [
        '120.83.49.90:9000',
        '95.189.112.214:35508',
    ]

    # 攔截所有未發生異常的請求
    def process_request(self, request, spider):

        print(111)
        # 使用UA池進行請求的UA偽裝  # 為所有的請求添加 User-Agent
        request.headers["User-Agent"] = random.choice(self.user_agent_list)   #隨機選擇user-agent,便於偽裝身份 return None  # 如果這里返回的是response,那么就不再執行下面的方法了

    # 攔截所有的響應
    def process_response(self, request, response, spider):

        return response

    # 攔截產生異常的請求
    def process_exception(self, request, exception, spider):

        print(222)
        # 使用代理池進行請求代理ip的設置,
        if request.url.split(":")[0] == "http":
            request.meta["proxy"] = random.choice(self.PROXY_http)
        else:
            request.meta["proxy"] = random.choice(self.PROXY_https)

    def spider_opened(self, spider):
        spider.logger.info('Spider opened: %s' % spider.name)

 

# settings.py

  一定要選擇download_middlewares,  不能是spider_middlers

# Enable or disable spider middlewares
# See https://doc.scrapy.org/en/latest/topics/spider-middleware.html
#SPIDER_MIDDLEWARES = {
#    'middlePro.middlewares.MiddleproSpiderMiddleware': 543,
#}

# Enable or disable downloader middlewares
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = {
   'middlePro.middlewares.MiddleproDownloaderMiddleware': 543,       #添加該類
}

 

scrapy之selenium使用 

'''
在scrapy中使用selenium的編碼流程:
    1.在spider的構造方法中創建一個瀏覽器對象(作為當前spider的一個屬性)
    2.重寫spider的一個方法closed(self,spider),在該方法中執行瀏覽器關閉的操作
    3.在下載中間件的process_response方法中,通過spider參數獲取瀏覽器對象
    4.在中間件的process_response中定制基於瀏覽器自動化的操作代碼(獲取動態加載出來的頁面源碼數據)
    5.實例化一個響應對象,且將page_source返回的頁面源碼封裝到該對象中
    6.返回該新的響應對象
'''

示例1:爬取網易新聞中的標題(包含一些動態加載的數據)

# wangyi.py

# -*- coding: utf-8 -*-
import scrapy
from selenium import webdriver

class WangyiSpider(scrapy.Spider):
    name = 'wangyi'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['http://war.163.com/']

    def __init__(self):
        # 包含動態加載數據時,使用selenium
        self.bro = webdriver.Chrome(executable_path=r"E:\data\PythonStudy\安裝軟件(下載)\爬蟲安裝包\chromedriver.exe")

    def parse(self, response):
        print(2222)
        div_list = response.xpath('//div[@class="data_row news_article clearfix "]')
        for div in div_list:
            title = div.xpath('.//div[@class="news_title"]/h3/a/text()').extract_first()
            print(title)

    def close(self,spider):
        self.bro.quit() print('關閉瀏覽器')

# middlewares.py

from scrapy.http import HtmlResponse
import time

class
WangyiproDownloaderMiddleware(object): def process_request(self, request, spider): return None def process_response(self, request, response, spider): print('即將返回一個新的響應對象!!!') #如何獲取動態加載出來的數據 bro = spider.bro bro.get(url=request.url) sleep(3) #包含了動態加載出來的新聞數據 page_text = bro.page_source sleep(3) return HtmlResponse(url=spider.bro.current_url,body=page_text,encoding='utf-8',request=request) def process_exception(self, request, exception, spider): pass

# settings.py

#配置可通行的中間件,要寫在下載中間將中
DOWNLOADER_MIDDLEWARES
= { 'wangyiPro.middlewares.WangyiproDownloaderMiddleware': 543, }
USER_AGENT
= 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36' # Obey robots.txt rules ROBOTSTXT_OBEY = False

 


免責聲明!

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



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