安基網 首頁 編程 Python 查看內容

Pyppeteer:比selenium更高效的爬蟲界的新神器

2020-5-23 23:35| 投稿: xiaotiger |來自: 互聯網


免責聲明:本站系公益性非盈利IT技術普及網,本文由投稿者轉載自互聯網的公開文章,文末均已注明出處,其內容和圖片版權歸原網站或作者所有,文中所述不代表本站觀點,若有無意侵權或轉載不當之處請從網站右下角聯系我們處理,謝謝合作!

摘要: 當今大數據的時代,網絡爬蟲已經成為了獲取數據的一個重要手段。隨著互聯網的發展,前端技術也在不斷變化,數據的加載方式也不再是單純的服務端渲染了,F在你可以看到很多網站的數據可能都是通過接口的形式傳輸的,或者即使不是接口那也是一些 JSON 的數據,然后經過 JavaScript 渲染得出來的。這時, ...

當今大數據的時代,網絡爬蟲已經成為了獲取數據的一個重要手段。

隨著互聯網的發展,前端技術也在不斷變化,數據的加載方式也不再是單純的服務端渲染了,F在你可以看到很多網站的數據可能都是通過接口的形式傳輸的,或者即使不是接口那也是一些 JSON 的數據,然后經過 JavaScript 渲染得出來的。

這時,如果你還用 requests 來爬取內容,那就不管用了。因為 requests 爬取下來的只能是服務器端網頁的源碼,這和瀏覽器渲染以后的頁面內容是不一樣的。因為,真正的數據是經過 JavaScript 執行后,渲染出來的,數據來源可能是 Ajax,也可能是頁面里的某些 Data,或者是一些 ifame 頁面等。不過,大多數情況下極有可能是 Ajax 接口獲取的。

所以,很多情況我們需要分析 Ajax請求,分析這些接口的調用方式,通過抓包工具或者瀏覽器的“開發者工具”,找到數據的請求鏈接,然后再用程序來模擬。但是,抓包分析流的方式,也存在一定的缺點。

一是:因為有些接口帶著加密參數,比如 token、sign 等等,模擬難度較大;

二是:抓包的方式只適合量小的情況。如果有一百、一千個,甚至五千、一萬個網站要處理時,該如何處理?還一個一個分析數據流?一個一個去抓包嗎?

基于以上的兩個嚴重的缺點,那有沒有一種簡單粗暴的方法,既不需要分析數據流,不需要抓包,又適合大批量的網站采集呢?這時 Puppeteer、Pyppeteer、Selenium、Splash 等自動化框架出現了。使用這些框架獲取HTML源碼,這樣我們爬取到的源代碼就是JavaScript 渲染以后的真正的網頁代碼,數據自然就好提取了。同時,也就繞過分析 Ajax 和一些 JavaScript 邏輯的過程。這種方式就做到了可見即可爬,難度也不大,同時適合大批量的采集。由于是模擬瀏覽器,一些法律方面的問題可以繞過。畢竟,爬蟲有風險! 哈哈....

Selenium,作為一款知名的Web自動化測試框架,支持大部分主流瀏覽器,提供了功能豐富的API接口,常常被我們用作爬蟲工具來使用。然而selenium的缺點也很明顯,比如速度太慢、對版本配置要求嚴苛,最麻煩是經常要更新對應的驅動。

由于Selenium流行已久,現在稍微有點反爬的網站都會對selenium和webdriver進行識別,網站只需要在前端js添加一下判斷腳本,很容易就可以判斷出是真人訪問還是webdriver。雖然也可以通過中間代理的方式進行js注入屏蔽webdriver檢測,但是webdriver對瀏覽器的模擬操作(輸入、點擊等等)都會留下webdriver的標記,同樣會被識別出來,要繞過這種檢測,只有重新編譯webdriver,麻煩自不必說,難度不是一般大。

由于Selenium具有這些嚴重的缺點。pyperteer成為了爬蟲界的又一新星。相比于selenium具有異步加載、速度快、具備有界面/無界面模式、偽裝性更強不易被識別為機器人,同時可以偽裝手機平板等終端;雖然支持的瀏覽器比較單一,但在安裝配置的便利性和運行效率方面都要遠勝selenium。

pyppeteer無疑為防爬墻撕開了一道大口子,針對selenium的淘寶、美團、文書網等網站,目前可通過該庫使用selenium的思路繼續突破,毫不費勁。

01.Pyppeteer簡介

Pyppeteer其實是Puppeteer的Python版本,下面簡單介紹下Pyppeteer的兩大特點,chromium瀏覽器和asyncio框架:

1).chromium

Chromium是一款獨立的瀏覽器,是Google為發展自家的瀏覽器Google Chrome而開啟的計劃,相當于Chrome的實驗版,Chromium的穩定性不如Chrome但是功能更加豐富,而且更新速度很快,通常每隔數小時就有新的開發版本發布

2).asyncio

syncio是Python的一個異步協程庫,自3.4版本引入的標準庫,直接內置了對異步IO的支持,號稱是Python最有野心的庫,官網上有非常詳細的介紹:

02.安裝與使用

1).極簡安裝

使用pip install pyppeteer命令就能完成pyppeteer庫的安裝,至于chromium瀏覽器,只需要一條pyppeteer-install命令就會自動下載對應的最新版本chromium瀏覽器到pyppeteer的默認位置。

如果不運行pyppeteer-install命令,在第一次使用pyppeteer的時候也會自動下載并安裝chromium瀏覽器,效果是一樣的?偟膩碚f,pyppeteer比起selenium省去了driver配置的環節。

當然,出于某種原因,也可能會出現chromium自動安裝無法順利完成的情況,這時可以考慮手動安裝:首先,從下列網址中找到自己系統的對應版本,下載chromium壓縮包;

然后,將壓縮包放到pyppeteer的指定目錄下解壓縮,windows系統的默認目錄。其他系統下的默認目錄可以參照下面這幅圖:

2).使用

安裝完后就來試試效果。一起來看下面這段代碼,在main函數中,先是建立一個瀏覽器對象,然后打開新的標簽頁,訪問百度主頁,對當前頁面截圖并保存為“example.png”,最后關閉瀏覽器。前文也提到過,pyppeteer是基于asyncio構建的,所以在使用的時候需要用到async/await結構

現在網站或系統的開發,逐漸趨于前后端分離,這樣數據的傳入就需要通過接口的方式進行傳輸。所以Ajax、動態渲染數據采集逐漸成為常態,Pyppeteer的使用會越來越多;诜奖、便與管理的考量,需要整理Pyppeteer的工具類,提供給團隊使用,下面是我在工作中整理的一個簡單的工具類,共大家參考,由于內容有點多,大家可以去我WX(crawler-small-gun),那里有完整的工具類。

一部分工具類代碼

import asyncio, tkinter, traceback

import base64, time, random

from pyppeteer import launch

from com.fy.utils.http.UserAgentUtils import UserAgentUtils

from com.fy.utils.hash.HashUtils import Hash_Utils

from com.fy.utils.file.FileUtils import File_Utils

class PyppeteerBrowser:

def __init__(self):

self.hash = Hash_Utils()

self.url = None

self.ua = UserAgentUtils()

#"""使用tkinter獲取屏幕大小""")--OK--

def screen_size(self):

tk = tkinter.Tk()

width = tk.winfo_screenwidth()

height = tk.winfo_screenheight()

tk.quit()

return width, height

#構造一個瀏覽器對象; --OK--; 如果需要每次初始化新的瀏覽器對象,則userDataDir路徑必須不同,否則,始終是在第一次初始化的瀏覽器對象上進行操作,且容易出異常;

async def getbrowser(self, headless=False, userDataDir=None):

'''

參數:

?ignoreHTTPSErrors(bool):是否忽略 HTTPS 錯誤。默認為 False

?headless(bool):是否在無頭模式下運行瀏覽器。默認為 True除非appMode或devtools選項True

?executablePath (str):運行 Chromium 或 Chrome 可執行文件的路徑,而不是默認捆綁的 Chromium。如果指定之后就不需要使用默認的 Chromium 了,可以指定為已有的 Chrome 或 Chromium。

?slowMo (int | float):通過傳入指定的時間,可以減緩 Pyppeteer 的一些模擬操作。 (按指定的毫秒數減慢 pyppeteer 操作。)

?args (List [str]):傳遞給瀏覽器進程的附加參數(標志)。

?dumpio(bool):是否管道瀏覽器進程 stdout 和 stderr 進入process.stdout和process.stderr。默認為False。為 True時,可以解決chromium瀏覽器多開頁面卡死問題。

?userDataDir (str):用戶數據目錄的路徑。即用戶數據文件夾,即可以保留一些個性化配置和操作記錄。(比如登錄信息等;可以在以后打開時自動登錄;)

?env(dict):指定瀏覽器可見的環境變量。默認與 python 進程相同。

?devtools(bool):是否為每個選項卡自動打開 DevTools 面板。如果是此選項True,headless則將設置該選項 False。

?logLevel(int | str):用于打印日志的日志級別。默認值與根記錄器相同。

?autoClose(bool):腳本完成時自動關閉瀏覽器進程。默認為True。

?loop(asyncio.AbstractEventLoop):事件循環(實驗)。

?args:常用的有['--no-sandbox','--disable-gpu', '--disable-setuid-sandbox','--window-size=1440x900']

?dumpio: 不知道為什么,如果不加 dumpio=True 有時會出現瀏覽器卡頓

?autoClose:默認就好,不過如果你需要保持瀏覽器狀態,可以不關閉,下次直接連接這個已存在的瀏覽器

ignoreDefaultArgs (bool): 不使用 Pyppeteer 的默認參數,如果使用了這個參數,那么最好通過 args 參數來設定一些參數,否則可能會出現一些意想不到的問題。這個參數相對比較危險,慎用。

handleSIGINT (bool): 是否響應 SIGINT 信號,也就是可以使用 Ctrl + C 來終止瀏覽器程序,默認是 True。

handleSIGTERM (bool): 是否響應 SIGTERM 信號,一般是 kill 命令,默認是 True。

handleSIGHUP (bool): 是否響應 SIGHUP 信號,即掛起信號,比如終端退出操作,默認是 True。

launch_kwargs = {

# 控制是否為無頭模式

"headless": False,

# chrome啟動命令行參數

"args": [

# 瀏覽器代理 配合某些中間人代理使用

"--proxy-server=http://127.0.0.1:8008",

# 最大化窗口

"--start-maximized",

# 取消沙盒模式 沙盒模式下權限太小

"--no-sandbox",

# 不顯示信息欄 比如 chrome正在受到自動測試軟件的控制 ...

"--disable-infobars",

# log等級設置 在某些不是那么完整的系統里 如果使用默認的日志等級 可能會出現一大堆的warning信息

"--log-level=3",

# 設置UA

"--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",

],

# 用戶數據保存目錄 這個最好也自己指定一個目錄

# 如果不指定的話,chrome會自動新建一個臨時目錄使用,在瀏覽器退出的時候會自動刪除臨時目錄

# 在刪除的時候可能會刪除失。ú恢罏槭裁磿霈F權限問題,我用的windows) 導致瀏覽器退出失敗

# 然后chrome進程就會一直沒有退出 CPU就會狂飆到99%

"userDataDir": "",

}

'''

print("構造瀏覽器對象開始...")

args = [ "--start-maximized", '--no-sandbox', "--disable-infobars" , "--log-level=3"]

parameters = {}

if userDataDir == None:

parameters = {'headless': headless, #是否打開瀏覽器;False:打開瀏覽器;True:進程中運行;

'args': args,

'dumpio': True #'dumpio': True:解決chromium瀏覽器多開頁面卡死問題。

}

else:

parameters = {'headless': headless, #是否打開瀏覽器;False:打開瀏覽器;True:進程中運行;

'args': args,

"userDataDir": userDataDir,

'dumpio': True #'dumpio': True:解決chromium瀏覽器多開頁面卡死問題。

}

#注意:同一個用戶目錄(userDataDir)不能被兩個chrome進程使用,如果你要多開,記得分別指定用戶目錄。否則會報編碼錯誤。

self.browser = await launch(parameters)

self.page = await self.browser.newPage()#在此瀏覽器上創建新頁面并返回其對象

width, height = self.screen_size()

# 設置網頁可視區域大小

await self.page.setViewport({

"width": width,

"height": height

})


# 是否啟用JS,enabled設為False,則無渲染效果

await self.page.setJavaScriptEnabled(enabled=True)


#設置請求頭userAgent

await self.page.setUserAgent(self.ua.getheaders())

await self.preventCheckWebdriver(self.page)

print("構造瀏覽器對象完畢....", self.page)

#獲取當前操作的界面

async def getPage(self):

return self.page


#獲取當前page對象的鏈接;

async def getCurUrl(self, page):

if page == None:

page = self.page

return page.url


#打開一個新的界面;)--OK--

async def getnewpage(self):

return await self.browser.newPage()


#獲取當前操作的界面重新加載

async def reload(self):

await self.page.reload()


#當前操作界面返回

async def goBack(self):

await self.page.goBack()


#獲取當前操作的界面的URL

async def getPageUrl(self):

await self.page.url()


#打開連接;--OK--

async def open(self, url, timeout=60):

try:

if url == None:

print("當前傳入的【url】不能為空,參數錯誤!")

self.url = url

print("打開網頁:" + (url))

self.res = await self.page.goto(url, options={'timeout':int(timeout * 1000)})#打開連接;

await asyncio.sleep(1)#強行等待3秒

status = self.res.status

curUrl = self.page.url

await self.preventCheckWebdriver(self.page)

return status, curUrl

except:return 404, None


"

小編推薦:欲學習電腦技術、系統維護、網絡管理、編程開發和安全攻防等高端IT技術,請 點擊這里 注冊賬號,公開課頻道價值萬元IT培訓教程免費學,讓您少走彎路、事半功倍,好工作升職加薪!

本文出自:https://www.toutiao.com/i6802921787945386510/

免責聲明:本站系公益性非盈利IT技術普及網,本文由投稿者轉載自互聯網的公開文章,文末均已注明出處,其內容和圖片版權歸原網站或作者所有,文中所述不代表本站觀點,若有無意侵權或轉載不當之處請從網站右下角聯系我們處理,謝謝合作!


鮮花

握手

雷人

路過

雞蛋

相關閱讀

最新評論

 最新
返回頂部
洗衣店赚钱联系澳洁 街机竞技捕鱼红包下载 bet365百家乐 南京麻将下载免费版 我要下载那个贵州十一选五 篮球规则大全 白城麻将群一毛钱 云南快乐10分玩法 股票入门基础知识网 100元分辨真假钱窍门 上海天天彩选四开奖