scrapy的核心組件,post請求,日誌、請求參數,中間件的UA池和selenium的應用

一.scrapy的核心組件html

五大核心組件工做流程:web

引擎(Scrapy)chrome

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

調度器(Scheduler)瀏覽器

  用來接受引擎發過來的請求, 壓入隊列中, 並在引擎再次請求的時候返回. 能夠想像成一個URL(抓取網頁的網址或者說是連接)的優先隊列, 由它來決定下一個要抓取的網址是什麼, 同時去除重複的網址cookie

下載器(Downloader)併發

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

爬蟲(Spiders)dom

  爬蟲是主要幹活的, 用於從特定的網頁中提取本身須要的信息, 即所謂的實體(Item)。用戶也能夠從中提取出連接,讓Scrapy繼續抓取下一個頁面異步

項目管道(Pipeline)

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

二.scrapy的post請求

  爬蟲文件中的爬蟲類繼承到了Spider父類中的start_requests(self)這個方法,該方法就能夠對start_urls列表中的url發起請求

  def start_requests(self):
        for u in self.start_urls:
           yield scrapy.Request(url=u,callback=self.parse)
# -*- 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):
        data = {
            'kw':'dog'
        }
        for url in self.start_urls:
            yield scrapy.FormRequest(url=url,formdata=data,callback=self.parse)

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

三.scrapy的日誌等級和請求參數

1.日誌信息的種類

  ERROR: 通常錯誤

  WAENING: 警告

  INFO: 通常的信息

  DEBUG:調試信息

2.設置日誌信息輸出

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

    LOG_LEVEL = "指定日誌信息種類"

    LOG_FILE = "log.txt"

LOG_LEVEL = 'ERROR'
#LOG_FILE = './log.txt'

3.請求參數

示例:爬取www.id97.com電影網,將一級頁面中的電影名稱,類型,評分一級二級頁面中的上映時間,導演,片長進行爬取。

  爬蟲文件

import scrapy
from moviePro.items import MovieproItem

class MovieSpider(scrapy.Spider):
    name = 'movie'
    allowed_domains = ['www.id97.com']
    start_urls = ['http://www.id97.com/']

    def parse(self, response):
        div_list = response.xpath('//div[@class="col-xs-1-5 movie-item"]')

        for div in div_list:
            item = MovieproItem()
            item['name'] = div.xpath('.//h1/a/text()').extract_first()
            item['score'] = div.xpath('.//h1/em/text()').extract_first()
            #xpath(string(.))表示提取當前節點下全部子節點中的數據值(.)表示當前節點
            item['kind'] = div.xpath('.//div[@class="otherinfo"]').xpath('string(.)').extract_first()
            item['detail_url'] = div.xpath('./div/a/@href').extract_first()
            #請求二級詳情頁面,解析二級頁面中的相應內容,經過meta參數進行Request的數據傳遞
            yield scrapy.Request(url=item['detail_url'],callback=self.parse_detail,meta={'item':item})

    def parse_detail(self,response):
        #經過response獲取item
        item = response.meta['item']
        item['actor'] = response.xpath('//div[@class="row"]//table/tr[1]/a/text()').extract_first()
        item['time'] = response.xpath('//div[@class="row"]//table/tr[7]/td[2]/text()').extract_first()
        item['long'] = response.xpath('//div[@class="row"]//table/tr[8]/td[2]/text()').extract_first()
        #提交item到管道
        yield item

  items.py

import scrapy


class MovieproItem(scrapy.Item):
    # define the fields for your item here like:
    name = scrapy.Field()
    score = scrapy.Field()
    time = scrapy.Field()
    long = scrapy.Field()
    actor = scrapy.Field()
    kind = scrapy.Field()
    detail_url = scrapy.Field()

  管道文件

import json
class MovieproPipeline(object):
    def __init__(self):
        self.fp = open('data.txt','w')
    def process_item(self, item, spider):
        dic = dict(item)
        print(dic)
        json.dump(dic,self.fp,ensure_ascii=False)
        return item
    def close_spider(self,spider):
        self.fp.close()

4.如何提升scrapy的爬取效率

增長併發:
    默認scrapy開啓的併發線程爲32個,能夠適當進行增長。在settings配置文件中修改CONCURRENT_REQUESTS = 100值爲100,併發設置成了爲100。

下降日誌級別:
    在運行scrapy時,會有大量日誌信息的輸出,爲了減小CPU的使用率。能夠設置log輸出信息爲INFO或者ERROR便可。在配置文件中編寫:LOG_LEVEL = ‘INFO’

禁止cookie:
    若是不是真的須要cookie,則在scrapy爬取數據時能夠進制cookie從而減小CPU的使用率,提高爬取效率。在配置文件中編寫:COOKIES_ENABLED = False

禁止重試:
    對失敗的HTTP進行從新請求(重試)會減慢爬取速度,所以能夠禁止重試。在配置文件中編寫:RETRY_ENABLED = False

減小下載超時:
    若是對一個很是慢的連接進行爬取,減小下載超時能夠能讓卡住的連接快速被放棄,從而提高效率。在配置文件中進行編寫:DOWNLOAD_TIMEOUT = 10 超時時間爲10s

示例:爬取校花網校花圖片 www.521609.com

  爬蟲文件

import scrapy
from xiaohua.items import XiaohuaItem

class XiahuaSpider(scrapy.Spider):

    name = 'xiaohua'
    allowed_domains = ['www.521609.com']
    start_urls = ['http://www.521609.com/daxuemeinv/']

    pageNum = 1
    url = 'http://www.521609.com/daxuemeinv/list8%d.html'

    def parse(self, response):
        li_list = response.xpath('//div[@class="index_img list_center"]/ul/li')
        for li in li_list:
            school = li.xpath('./a/img/@alt').extract_first()
            img_url = li.xpath('./a/img/@src').extract_first()

            item = XiaohuaItem()
            item['school'] = school
            item['img_url'] = 'http://www.521609.com' + img_url

            yield item

        if self.pageNum < 10:
            self.pageNum += 1
            url = format(self.url % self.pageNum)
            #print(url)
            yield scrapy.Request(url=url,callback=self.parse)

  items.py

import scrapy


class XiaohuaItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    school=scrapy.Field()
    img_url=scrapy.Field()

  管道文件

import json
import os
import urllib.request
class XiaohuaPipeline(object):
    def __init__(self):
        self.fp = None

    def open_spider(self,spider):
        print('開始爬蟲')
        self.fp = open('./xiaohua.txt','w')

    def download_img(self,item):
        url = item['img_url']
        fileName = item['school']+'.jpg'
        if not os.path.exists('./xiaohualib'):
            os.mkdir('./xiaohualib')
        filepath = os.path.join('./xiaohualib',fileName)
        urllib.request.urlretrieve(url,filepath)
        print(fileName+"下載成功")

    def process_item(self, item, spider):
        obj = dict(item)
        json_str = json.dumps(obj,ensure_ascii=False)
        self.fp.write(json_str+'\n')

        #下載圖片
        self.download_img(item)
        return item

    def close_spider(self,spider):
        print('結束爬蟲')
        self.fp.close()

  setting.py

USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

# Configure maximum concurrent requests performed by Scrapy (default: 16)
CONCURRENT_REQUESTS = 100
COOKIES_ENABLED = False
LOG_LEVEL = 'ERROR'
RETRY_ENABLED = False
DOWNLOAD_TIMEOUT = 3
# Configure a delay for requests for the same website (default: 0)
# See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
# The download delay setting will honor only one of:
#CONCURRENT_REQUESTS_PER_DOMAIN = 16
#CONCURRENT_REQUESTS_PER_IP = 16
DOWNLOAD_DELAY = 3

參考:http://www.javashuo.com/article/p-tpzlcfow-cv.html

四.scrapy中間件的UA池和代理池

1.中間件

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

做用:

  引擎將請求傳遞給下載器過程當中, 下載中間件能夠對請求進行一系列處理

  在下載器完成將Response傳遞給引擎中,下載中間件能夠對響應進行一系列處理

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

2.UA池  (User-Agent池)

做用:

  儘量多的將scrapy工程中的請求假裝成不一樣類型的瀏覽器身份

操做流程:

  在下載中間件中攔截請求

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

  在配置文件中開啓下載中間件

from scrapy.contrib.downloadermiddleware.useragent import UserAgentMiddleware
import random
#UA池代碼的編寫(單獨給UA池封裝一個下載中間件的一個類)
class RandomUserAgent(UserAgentMiddleware):

    def process_request(self, request, spider):
        #從列表中隨機抽選出一個ua值
        ua = random.choice(user_agent_list)
        #ua值進行當前攔截到請求的ua的寫入操做
        request.headers.setdefault('User-Agent',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"
]

3.代理池

做用:

  儘量多的將scrapy工程中的請求的IP設置成不一樣的

操做流程:

  在下載中間件中攔截請求

  將攔截的請求的IP修改爲某一代理IP

  在配置文件中開啓下載中間件

#批量對攔截到的請求進行ip更換
#單獨封裝下載中間件類
class Proxy(object):
    def process_request(self, request, spider):
        #對攔截到請求的url進行判斷(協議頭究竟是http仍是https)
        #request.url返回值:http://www.xxx.com
        h = request.url.split(':')[0]  #請求的協議頭
        if h == 'https':
            ip = random.choice(PROXY_https)
            request.meta['proxy'] = 'https://'+ip
        else:
            ip = random.choice(PROXY_http)
            request.meta['proxy'] = 'http://' + ip

#可被選用的代理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',
]

五.scrapy中的selenium的應用

使用流程:

  在spider的構造方法中建立一個瀏覽器對象(做爲當前spider的一個屬性)

  重寫spider的一個方法closed(self.spider),在該方法中執行瀏覽器關閉操做

  在下載中間件的process_response方法中,經過spider參數獲取瀏覽器對象

  在中間件的process_response中定製基於瀏覽器自動化的操做代碼(獲取動態加載出來的頁面源碼數據)

  實例化一個響應對象,且將page_source返回的頁面源碼封裝到該對象中

  返回該新的響應對象

示例:

  爬蟲文件

class WangyiSpider(RedisSpider):
    name = 'wangyi'
    #allowed_domains = ['www.xxxx.com']
    start_urls = ['https://news.163.com']
    def __init__(self):
        #實例化一個瀏覽器對象(實例化一次)
        self.bro = webdriver.Chrome(executable_path='/Users/bobo/Desktop/chromedriver')

    #必須在整個爬蟲結束後,關閉瀏覽器
    def closed(self,spider):
        print('爬蟲結束')
        self.bro.quit()

  中間件文件

from scrapy.http import HtmlResponse    
    #參數介紹:
    #攔截到響應對象(下載器傳遞給Spider的響應對象)
    #request:響應對象對應的請求對象
    #response:攔截到的響應對象
    #spider:爬蟲文件中對應的爬蟲類的實例
    def process_response(self, request, response, spider):
        #響應對象中存儲頁面數據的篡改
        if request.url in['http://news.163.com/domestic/','http://news.163.com/world/','http://news.163.com/air/','http://war.163.com/']:
            spider.bro.get(url=request.url)
            js = 'window.scrollTo(0,document.body.scrollHeight)'
            spider.bro.execute_script(js)
            time.sleep(2)  #必定要給與瀏覽器必定的緩衝加載數據的時間
            #頁面數據就是包含了動態加載出來的新聞數據對應的頁面數據
            page_text = spider.bro.page_source
            #篡改響應對象
            return HtmlResponse(url=spider.bro.current_url,body=page_text,encoding='utf-8',request=request)
        else:
            return response

  配置文件

DOWNLOADER_MIDDLEWARES = {
    'wangyiPro.middlewares.WangyiproDownloaderMiddleware': 543,

}

參考:http://www.javashuo.com/article/p-myajiybf-dc.html

相關文章
相關標籤/搜索