1. 程式人生 > >【python學習筆記】38:使用Selenium抓取去哪兒網動態頁面

【python學習筆記】38:使用Selenium抓取去哪兒網動態頁面

學習《Python3爬蟲、資料清洗與視覺化實戰》時自己的一些實踐。


去哪兒網PC端自由行頁面,使用者需要輸入出發地和目的地,點選開始定製,然後就可以看到一系列相關的旅遊產品。在這個旅遊產品頁換頁不會改變URL,而是重新載入,這時頁碼沒有體現在URL中,這種動態頁面用傳統的爬蟲實現不了。

安裝配置

Selenium本身用Anaconda安裝,作為模擬使用者行為的自動化測試工具,它另外還要使用瀏覽器驅動。在這篇裡講述了Chrome和其驅動ChromeDriver的相容關係,驅動可以直接在官網下載,解壓後直接放在系統環境變數目錄下就可以,我放在Anaconda目錄下了。

XPath的選取和使用

XPath使用路徑表示式來選取XML文件中的節點或節點集,在Chrome中通過檢查元素可以很方便的定位並獲取HTML中某個或某些元素的XPath:
在這裡插入圖片描述圖中元素的XPath是//*[@id="list"]/div[2],這表示它是該列表中的第二個div,如果需要選取整個列表,在使用時XPath只要不指明下標就可以了,在這裡也就是//*[@id="list"]/div

在使用時,注意driver.find_element_by_xpath()返回的是一個WebElement物件,driver.find_elements_by_xpath()才能返回可迭代的一系列物件,兩個函式僅有一個字母s之差,很容易弄混。

爬蟲程式碼

import requests
import urllib.request
import time
import random
from selenium import webdriver
from selenium.webdriver.common.by import By  # 用於指定HTML檔案中的DOM元素
from selenium.webdriver.support.ui import WebDriverWait  # 用於等待網頁載入完成
from selenium.webdriver.support import expected_conditions as
EC # 用於指定標誌網頁載入結束的條件 ''' 去哪網PC端自由行 https://fh.dujia.qunar.com/?tf=package ChromeDriver下載 https://npm.taobao.org/mirrors/chromedriver ''' # 出發地城市列表 dep_citys = ['北京', '上海', '杭州', '南京', '深圳', '成都'] # 每次傳送請求隔一會(模擬使用者的輸入和檢查較慢) def get_resp(url): time.sleep(5) return requests.get(url) if __name__ == '__main__': # 控制迴圈次數 j = k = 0 # 用驅動開啟Chrome瀏覽器 driver = webdriver.Chrome() # 對每個出發地 for dep in dep_citys: url = 'https://touch.dujia.qunar.com/golfz/sight/arriveRecommend?dep={}&exclude=&extensionImg=255,175'.format( urllib.request.quote(dep)) response = get_resp(url) # 查詢到的就是該出發地選定後供選擇的若干目的地 arrv_dict = response.json() for data_it in arrv_dict['data']: # 這裡得到的是列表中的一項項dict j += 1 if j > 4: break for subMod_it in data_it['subModules']: # 該dict裡面subModules列表裡的每一項 k += 1 if k > 6: break for item_it in subMod_it['items']: # 該項的item欄位所示列表的每一項 # 通過瀏覽器開啟網頁 driver.get('https://fh.dujia.qunar.com/?tf=package') # WebDriverWait(driver, 10)意思是使driver保持等待,最多10秒 # .until()裡指定等待的是什麼事件 # EC.presence_of_element_located()裡面指定標誌等待結束的DOM元素 # 裡面傳入元組(By.ID, "depCity")意思是等待id="depCity"的元素載入完成 WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "depCity"))) # 在Chrome檢查元素後,直接右鍵Copy XPath即可選擇相應的元素! # 將出發地清空 driver.find_element_by_xpath("//*[@id='depCity']").clear() # 將出發地寫進去 driver.find_element_by_xpath("//*[@id='depCity']").send_keys(dep) # 將目的地寫進去 driver.find_element_by_xpath("//*[@id='arrCity']").send_keys(item_it['query']) # 點選[開始定製]按鈕 driver.find_element_by_xpath("/html/body/div[2]/div[1]/div[2]/div[3]/div/div[2]/div/a").click() print("dep:%s arrv:%s" % (dep, item_it['query'])) # 最多抓3頁 for i in range(3): time.sleep(random.uniform(5, 6)) # 隨機等待5~6秒,模擬使用者每頁看個五六秒 # 關於[下一頁]按鈕:在不同的頁上,下一頁按鈕的XPath是不一樣的,比如下面兩個 # // *[ @ id = "pager"] / div / a[8] # // *[ @ id = "pager"] / div / a[7] # 因此不能通過這種方式來實現點選下一頁 # 可以用XPath獲得翻頁的整塊元素,然後在其中找'下一頁'按鈕 page_btn_a_s = driver.find_elements_by_xpath('//*[@id="pager"]/div/a') # 如果獲取不到頁碼按鈕,說明從出發地到目的地沒有產品,直接跳出 if not page_btn_a_s: break # 旅行方案產品列表 routes = driver.find_elements_by_xpath('//*[@id="list"]/div') # 如果第一頁就沒有旅行產品(如北京到泰國),那麼後面的頁也不會有 if not routes: break for route in routes: result = { 'date': time.strftime('%Y-%m-%d', time.localtime(time.time())), 'dep': dep, 'arrv': item_it['query'], 'result': route.text } print(result) # 這裡可以做存到資料庫的操作 has = False # 記錄是否找得到'下一頁' for a in page_btn_a_s: if a.text == u"下一頁": has = True a.click() break if not has: # 如果沒找到下一頁 break # 說明已經是最後一頁,結束這一系產品的迴圈

執行結果

在這裡插入圖片描述

善後處理

後臺可能還存在chromedriver程序:
在這裡插入圖片描述
工作管理員裡右鍵->結束程序樹。