引言
Selenium 在被使用的時候有個麻煩事,就是環境的相關配置,得安裝好相關瀏覽器,好比 Chrome、Firefox 等等,而後還要到官方網站去下載對應的驅動,最重要的還須要安裝對應的 Python Selenium 庫,確實是否是很方便,另外若是要作大規模部署的話,環境配置的一些問題也是個頭疼的事情。那麼本節就介紹另外一個相似的替代品,叫作 Pyppeteer。html
Pyppeteer簡介
注意,本節講解的模塊叫作 Pyppeteer,不是 Puppeteer。Puppeteer 是 Google 基於 Node.js 開發的一個工具,有了它咱們能夠經過 JavaScript 來控制 Chrome 瀏覽器的一些操做,固然也能夠用做網絡爬蟲上,其 API 極其完善,功能很是強大。 而 Pyppeteer 又是什麼呢?它其實是 Puppeteer 的 Python 版本的實現,但他不是 Google 開發的,是一位來自於日本的工程師依據 Puppeteer 的一些功能開發出來的非官方版本。git
在 Pyppetter 中,實際上它背後也是有一個相似 Chrome 瀏覽器的 Chromium 瀏覽器在執行一些動做進行網頁渲染,首先說下 Chrome 瀏覽器和 Chromium 瀏覽器的淵源。github
Chromium 是谷歌爲了研發 Chrome 而啓動的項目,是徹底開源的。兩者基於相同的源代碼構建,Chrome 全部的新功能都會先在 Chromium 上實現,待驗證穩定後纔會移植,所以 Chromium 的版本更新頻率更高,也會包含不少新的功能,但做爲一款獨立的瀏覽器,Chromium 的用戶羣體要小衆得多。兩款瀏覽器「同根同源」,它們有着一樣的 Logo,但配色不一樣,Chrome 由藍紅綠黃四種顏色組成,而 Chromium 由不一樣深度的藍色構成。
Pyppeteer 就是依賴於 Chromium 這個瀏覽器來運行的。那麼有了 Pyppeteer 以後,咱們就能夠免去那些繁瑣的環境配置等問題。若是第一次運行的時候,Chromium 瀏覽器沒有安裝,那麼程序會幫咱們自動安裝和配置,就免去了繁瑣的環境配置等工做。另外 Pyppeteer 是基於 Python 的新特性 async 實現的,因此它的一些執行也支持異步操做,效率相對於 Selenium 來講也提升了。web
環境安裝
- 因爲 Pyppeteer 採用了 Python 的 async 機制,因此其運行要求的 Python 版本爲 3.5 及以上
- pip install pyppeteer
快速上手
- 爬取http://quotes.toscrape.com/js/ 所有頁面數據瀏覽器
import asyncio
from pyppeteer import launch
from lxml import etree
async def main():
browser = await launch()
page = await browser.newPage()
await page.goto('http://quotes.toscrape.com/js/')
page_text = await page.content()
tree = etree.HTML(page_text)
div_list = tree.xpath('//div[@class="quote"]')
print(len(div_list))
await browser.close()
asyncio.get_event_loop().run_until_complete(main())
運行結果:10
解釋:launch 方法會新建一個 Browser 對象,而後賦值給 browser,而後調用 newPage 方法至關於瀏覽器中新建了一個選項卡,同時新建了一個 Page 對象。而後 Page 對象調用了 goto 方法就至關於在瀏覽器中輸入了這個 URL,瀏覽器跳轉到了對應的頁面進行加載,加載完成以後再調用 content 方法,返回當前瀏覽器頁面的源代碼。而後進一步地,咱們用 pyquery 進行一樣地解析,就能夠獲得 JavaScript 渲染的結果了。在這個過程當中,咱們沒有配置 Chrome 瀏覽器,沒有配置瀏覽器驅動,免去了一些繁瑣的步驟,一樣達到了 Selenium 的效果,還實現了異步抓取,爽歪歪!網絡
詳細用法
- 開啓瀏覽器
- 調用 launch 方法便可,相關參數介紹:
- ignoreHTTPSErrors (bool): 是否要忽略 HTTPS 的錯誤,默認是 False。
- headless (bool): 是否啓用 Headless 模式,即無界面模式,若是 devtools 這個參數是 True 的話,那麼該參數就會被設置爲 False,不然爲 True,即默認是開啓無界面模式的。
- executablePath (str): 可執行文件的路徑,若是指定以後就不須要使用默認的 Chromium 了,能夠指定爲已有的 Chrome 或 Chromium。
- args (List[str]): 在執行過程當中能夠傳入的額外參數。
- devtools (bool): 是否爲每個頁面自動開啓調試工具,默認是 False。若是這個參數設置爲 True,那麼 headless 參數就會無效,會被強制設置爲 False。
- 調用 launch 方法便可,相關參數介紹:
- 關閉提示條:」Chrome 正受到自動測試軟件的控制」,這個提示條有點煩,那咋關閉呢?這時候就須要用到 args 參數了,禁用操做以下:
browser = await launch(headless=False, args=['--disable-infobars'])
-
處理頁面顯示問題:訪問淘寶首頁app
import asyncio
from pyppeteer import launch
async def main():
browser = await launch(headless=False)
page = await browser.newPage()
await page.goto('https://www.taobao.com')
await asyncio.sleep(10)
asyncio.get_event_loop().run_until_complete(main())
發現頁面顯示出現了問題,須要手動調用setViewport方法設置顯示頁面的長寬像素。設置以下:lessimport asyncio
from pyppeteer import launch
width, height = 1366, 768
async def main():
browser = await launch(headless=False)
page = await browser.newPage()
await page.setViewport({'width': width, 'height': height})
await page.goto('https://www.taobao.com')
await asyncio.sleep(3)
asyncio.get_event_loop().run_until_complete(main())
-
執行js程序:拖動滾輪。調用evaluate方法。dom
import asyncio
from pyppeteer import launch
width, height = 1366, 768
async def main():
browser = await launch(headless=False)
page = await browser.newPage()
await page.setViewport({'width': width, 'height': height})
await page.goto('https://movie.douban.com/typerank?type_name=%E5%8A%A8%E4%BD%9C&type=5&interval_id=100:90&action=')
await asyncio.sleep(3)
#evaluate能夠返回js程序的返回值
dimensions = await page.evaluate('window.scrollTo(0,document.body.scrollHeight)')
await asyncio.sleep(3)
print(dimensions)
await browser.close()
asyncio.get_event_loop().run_until_complete(main())
-
規避webdriver檢測:異步
import asyncio
from pyppeteer import launch
async def main():
browser = await launch(headless=False, args=['--disable-infobars'])
page = await browser.newPage()
await page.goto('https://login.taobao.com/member/login.jhtml?redirectURL=https://www.taobao.com/')
await page.evaluate(
'''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } }) }''')
await asyncio.sleep(10)
asyncio.get_event_loop().run_until_complete(main())
- UA假裝:
await self.page.setUserAgent('xxx')
-
節點交互
import asyncio
from pyppeteer import launch
async def main():
# headless參數設爲False,則變成有頭模式
browser = await launch(
headless=False
)
page = await browser.newPage()
# 設置頁面視圖大小
await page.setViewport(viewport={'width': 1280, 'height': 800})
await page.goto('https://www.baidu.com/')
#節點交互
await page.type('#kw','周杰倫',{'delay': 1000})
await asyncio.sleep(3)
await page.click('#su')
await asyncio.sleep(3)
#使用選擇器選中標籤進行點擊
alist = await page.querySelectorAll('.s_tab_inner > a')
a = alist[3]
await a.click()
await asyncio.sleep(3)
await browser.close()
asyncio.get_event_loop().run_until_complete(main())
綜合練習
-
爬取頭條和網易的新聞標題
import asyncio
from pyppeteer import launch
from lxml import etree
async def main():
# headless參數設爲False,則變成有頭模式
browser = await launch(
headless=False
)
page1 = await browser.newPage()
# 設置頁面視圖大小
await page1.setViewport(viewport={'width': 1280, 'height': 800})
await page1.goto('https://www.toutiao.com/')
await asyncio.sleep(2)
# 打印頁面文本
page_text = await page1.content()
page2 = await browser.newPage()
await page2.setViewport(viewport={'width': 1280, 'height': 800})
await page2.goto('https://news.163.com/domestic/')
await page2.evaluate('window.scrollTo(0,document.body.scrollHeight)')
page_text1 = await page2.content()
await browser.close()
return {'wangyi':page_text1,'toutiao':page_text}
def parse(task):
content_dic = task.result()
wangyi = content_dic['wangyi']
toutiao = content_dic['toutiao']
tree = etree.HTML(toutiao)
a_list = tree.xpath('//div[@class="title-box"]/a')
for a in a_list:
title = a.xpath('./text()')[0]
print('toutiao:',title)
tree = etree.HTML(wangyi)
div_list = tree.xpath('//div[@class="data_row news_article clearfix "]')
print(len(div_list))
for div in div_list:
title = div.xpath('.//div[@class="news_title"]/h3/a/text()')[0]
print('wangyi:',title)
tasks = []
task1 = asyncio.ensure_future(main())
task1.add_done_callback(parse)
tasks.append(task1)
asyncio.get_event_loop().run_until_complete(asyncio.wait(tasks))
爬取結果:toutiao: 「央視快評」堅守初心 爲國奉獻toutiao: 南航一A380客機北京降落時遭冰雹風擋現裂痕 已平安降落無人受傷toutiao: 美國正開啓第二戰場:圍獵中國高科技企業 |「雙線做戰」戰略意圖toutiao: 雲南省陸良縣:農民給供銷社打「白條」toutiao: 媒體:90後副縣長若非靠拼爹上位 需拿出業績服衆toutiao: 南航A380飛北京客機遭遇冰雹襲擊,擋風玻璃全碎toutiao: 祕魯北部發生7.8級地震toutiao: 1958年,由捷克斯洛伐克援建的北京電影洗印廠曾爲全國行業的老大toutiao: 一箭60星,發射成功!馬斯克衛星互聯網計劃啓動69wangyi: 中美經貿摩擦背後:有人在幹,有人在騙wangyi: 華爲迴應個別標準組織撤銷資格:產品服務不受影響wangyi: 隔空約架?中方主播劉欣23年前就贏得國際演講比賽wangyi: 從錢學森到任正非 中國教育有多少底氣應對全球化wangyi: 2個月內二度履新 35歲清華博士任安徽省直單位領導wangyi: 南陽「水氫發動機汽車」引熱議 官方迴應四大疑問wangyi: 31歲北大博士躋身縣委常委 主筆6萬字全縣發展規劃wangyi: 幹部退休15年後投案自首 省委巡視辦:頭一次碰到wangyi: 臺灣被標註"中國臺灣省" 臺外事部門要求更正被拒wangyi: 190天3次現場辦公!南陽領導爲什麼鍾愛青年汽車項目