關於使用scrapy框架編寫爬蟲以及Ajax動態加載問題、反爬問題解決方案


Python爬蟲總結

 

總的來說,Python爬蟲所做的事情分為兩個部分,1:將網頁的內容全部抓取下來,2:對抓取到的內容和進行解析,得到我們需要的信息。

 

目前公認比較好用的爬蟲框架為Scrapy,而且直接使用框架比自己使用requestsbeautifulsoupre包編寫爬蟲更加方便簡單。

 

1、關於Scrapy框架

 

簡介 Scrapy是一個為了爬取網站數據,提取結構性數據而編寫的應用框架。 其最初是為了 頁面抓取 (更確切來說, 網絡抓取 )所設計的, 也可以應用在獲取API所返回的數據(例如 Amazon Associates Web Services ) 或者通用的網絡爬蟲。

 

官方文檔地址  http://scrapy-chs.readthedocs.io/zh_CN/1.0/index.html

 

Scrapy安裝   pip install Scrapy

 

創建Scrapy項目 scrapy startproject scrapyspider(projectname)

該命令創建包涵下列內容的目錄:

 

這些文件分別是:

  • scrapy.cfg: 項目的配置文件。
  • scrapyspider/: 該項目的python模塊。之后您將在此加入代碼。
  • scrapyspider/items.py: 項目中的item文件。
  • scrapyspider/pipelines.py: 項目中的pipelines文件,用來執行保存數據的操作
  • scrapyspider/settings.py: 項目的設置文件。
  • scrapyspider/spiders/: 放置爬蟲代碼的目錄。

 

  

 

 

 編寫爬蟲以爬取豆瓣電影TOP250為例展示一個完整但簡單的Scrapy爬蟲的流程

 

  • 首先,在items.py文件中聲明需要提取的數據,Item 對象是種簡單的容器,保 存了爬取到得數據。 其提供了 類似於詞典(dictionary-like) API以及用於聲明可 用字段的簡單語法。許多Scrapy組件使用了Item提供的額外信息: exporter根據 Item聲明的字段來導出 數據、 序列化可以通過Item字段的元數據(metadata) 定義、trackref 追蹤Item 實例來幫助尋找內存泄露 (see 使用 trackref 調試內 存泄露) 等等。
  • Item使用簡單的class定義語法以及Field對象來聲明。我們打開scrapyspider目錄下的items.py文件寫入下列代碼聲明Item

為了創建一個爬蟲,首先需要繼承scrapy.Spider類,定義以下三個屬性:

1、name : 用於區別不同的爬蟲,名字必須是唯一的。

2、start_urls: 包含了Spider在啟動時進行爬取的url列表。

3、parse() spider的一個函數。 被調用時,每個初始URL完成下載后生成的 Response 對象將會作為唯一的參數傳遞給該函數,然后解析提取數據。

 

 

scrapyspider/spiders目錄下創建douban_spider.py文件,並寫入初步的代碼:

 

from scrapy import Request

from scrapy.spiders import Spider

from scrapyspider.items import DoubanMovieItem

 

 

class DoubanMovieTop250Spider(Spider):

    name = 'douban_movie_top250'

    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36',}#設置請求頭文件,模擬瀏覽器訪問(涉及反爬機制)

 

    def start_requests(self):#該函數定義需要爬取的初始鏈接並下載網頁內容

        url = 'https://movie.douban.com/top250'

        yield Request(url, headers=self.headers)

 

    def parse(self, response):

        item = DoubanMovieItem()

        movies = response.xpath('//ol[@class="grid_view"]/li') #使用xpath對下載到的網頁源碼進行解析

        for movie in movies:

            item['ranking'] = movie.xpath(

                './/div[@class="pic"]/em/text()').extract()[0]

            item['movie_name'] = movie.xpath(

                './/div[@class="hd"]/a/span[1]/text()').extract()[0]

            item['score'] = movie.xpath(

                './/div[@class="star"]/span[@class="rating_num"]/text()'

            ).extract()[0]

            item['score_num'] = movie.xpath(

                './/div[@class="star"]/span/text()').re(ur'(\d+)人評價')[0]

            yield item

        next_url =  response.xpath('//span[@class="next"]/a/@href').extract() #解析得到下一頁的鏈接

        if next_url:

            next_url = 'https://movie.douban.com/top250' + next_url[0]

            yield Request(next_url, headers=self.headers) #下載下一頁的網頁內容

 

運行爬蟲 在項目文件夾內打開cmd運行下列命令:

 

此處的douban_movie_top250即為我們剛剛寫的爬蟲的name, -o douban.csvscrapy提供的功能,將item輸出為csv格式的文件,存儲到douban.csv中。

得到數據:

 

 

 

到此我們已經可以解決一般普通網站的抓取任務,普通網站是指網頁源碼之中包含了所有我們想要抓取的內容,但是有的時候一些網站采用了Ajax異步加載的方法,導致以上介紹的方法無法使用。

 

2、關於抓取Ajax異步加載的網站

 

Ajax是什么:

 

AJAX即“Asynchronous Javascript And XML”(異步JavaScriptXML),是指一種創建交互式網頁應用的網頁開發技術。

通過在后台與服務器進行少量數據交換,AJAX 可以使網頁實現異步更新。這意味着可以在不重新加載整個網頁的情況下,對網頁的某部分進行更新。

通過Ajax異步加載的網頁內容在網頁源碼中是沒有的,也就是之前介紹的方法中下載到的response中是解析不到我們想要的內容的。

 

如何抓取AJAX異步加載頁面

 

對於這類網頁,我們一般采用兩種方法:

1、通過抓包找到異步加載請求的真正地址

2、通過PhantomJS等無頭瀏覽器執行JS代碼后再抓取

但是通常采取第一種方法,因為第二種方法使用無頭瀏覽器會大大降低抓取的效率。

 

異步加載網站抓取示例

使用豆瓣電影分類排行榜作為抓取示例,鏈接為

https://movie.douban.com/typerank?type_name=%E5%8A%A8%E4%BD%9C&type=5&interval_id=100:90&action=

電影信息網頁源碼中沒有,並且采用鼠標下拉更新頁面,這時需要我們在需要抓取的頁面打開Chrome的開發者工具,選擇network,實現一次下拉刷新

 

 

發現新增了一個get請求,並且響應為JSON格式。觀察JSON的內容,發現正是需要抓取的內容。

抓取內容的問題解決了,接下來處理多頁抓取問題,因為請求為get形式,所以首先進行幾次下拉刷新,觀察請求鏈接的變化,會發現請求的地址中只有start的值在變化,並且每次刷新增加20,其他都不變,所以我們更改這個參數就可以實現翻頁。

由於之前已經在items.py中對需要抓取的數據做了聲明,所以只需要在scraoyspider/spiders目錄下創建一個新的爬蟲文件douban_actions.py,代碼如下:

import re

import json

 

from scrapy import Request

from scrapy.spiders import Spider

from scrapyspider.items import DoubanMovieItem

 

class DoubanAJAXSpider(Spider):

    name = 'douban_ajax' #設置爬蟲名字為douban_ajax

    headers = {

        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36',

    } #設置請求頭文件,模擬瀏覽器訪問(涉及反爬機制)

    def start_requests(self):

        url = 'https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&start =0&limit=20'

        yield Request(url, headers=self.headers)

 

    def parse(self, response):

        datas = json.loads(response.body)#Json格式數據處理為字典類型

        item = DoubanMovieItem()

        if datas:

            for data in datas:

                item['ranking'] = data['rank']

                item['movie_name'] = data['title']

                item['score'] = data['score']

                item['score_num'] = data['vote_count']

                yield item

 

            # 如果datas存在數據則對下一頁進行采集

            page_num = re.search(r'start=(\d+)', response.url).group(1)

            page_num = 'start=' + str(int(page_num)+20)

            next_url = re.sub(r'start=\d+', page_num, response.url)

    #處理鏈接

            yield Request(next_url, headers=self.headers)

    #請求下一頁

 

運行爬蟲

 

  scrapy crawl douban_ajax -o douban_movie.csv

 

 

然而,很多時候ajax請求都會經過后端鑒權,不能直接構造URL獲取。這時就可以通過PhantomJSchromedriver等配合Selenium模擬瀏覽器動作,抓取經過js渲染后的頁面。

使用這種方法有時會遇到定位網頁頁面元素定位不准的情況,這時就要注意網頁中的frame標簽,frame標簽有framesetframeiframe三種,frameset跟其他普通標簽沒有區別,不會影響到正常的定位,而frameiframeselenium定位而言是一樣的,需要進行frame的跳轉。(這兩點暫不展開,在抓取中財網—數據引擎網站時就遇到此類問題)

 

 

彩蛋

兩個提高效率的Chrome插件

  Toggle JavaScript  (檢測網頁哪些內容使用了異步加載)  

  JSON-handle (格式化Json串)

 

 

3、關於突破爬蟲反爬機制

 

   目前使用到的反反爬手段主要有三個:

 

1、在請求之間設置延時,限制請求速度。(使用python time庫)

 

2、在每次請求時都隨機使用用戶代理User-Agent,為了方便,在scrapy框架中,可以使用fake-useragent這個開源庫。

Github地址:https://github.com/hellysmile/fake-useragent

 

3、使用高匿代理ip,同樣為了方便,在scrapy框架中編寫爬蟲,建議使用開源庫 scrapy-proxies

Github地址:https://github.com/aivarsk/scrapy-proxies

 

參考內容地址:https://zhuanlan.zhihu.com/p/24769534


免責聲明!

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



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