Python3.x:Selenium+PhantomJS爬取帶Ajax、Js的網頁
前言
現在很多網站的都大量使用JavaScript,或者使用了Ajax技術。這樣在網頁加載完成后,url雖然不改變但是網頁的DOM元素內容卻可以動態的變化。如果處理這種網頁是還用requests庫或者python自帶的urllib庫那么得到的網頁內容和網頁在瀏覽器中顯示的內容是不一致的。
解決方案
使用Selenium+PhantomJS。這兩個組合在一起,可以運行非常強大的爬蟲,可以處理cookie,JavaScript,header以及其他你想做的任何事情。
安裝第三方庫
Selenium是一個強大的網絡數據采集工具,最初是為網站自動化測試開發的,其有對應的Python庫;
Selenium安裝命令:
pip install selenium
安裝PhantomJS
PhantomJS是一個基於webkit內核的無頭瀏覽器,即沒有UI界面,即它就是一個瀏覽器,只是其內的點擊、翻頁等人為相關操作需要程序設計實現。通過編寫js程序可以直接與webkit內核交互,在此之上可以結合java語言等,通過java調用js等相關操作。需要去官網下載對應平台的壓縮文件;
PhantomJS(phantomjs-2.1.1-windows)下載地址:http://phantomjs.org/download.html
下載PhantomJs 然后將 解壓后的執行文件放在被設置過環境變量的地方,不設置的話,后續代碼就要設, 所以這里直接放進來方便;
然后檢測下,在cmd窗口輸入phantomjs:
出現這樣的畫面,即表示成功;
示例一:
Selenium+PhantomJS示例代碼:
from selenium import webdriver driver = webdriver.PhantomJS() driver.get('http://www.cnblogs.com/lizm166/p/8360388.html') #獲取網頁源碼 data = driver.page_source print(data) #獲取元素的html源碼 tableData = driver.find_element_by_tag_name('tableData').get_attribute('innerHTML') #獲取元素的id值 tableI = driver.find_element_by_tag_name('tableData').get_attribute('id') #獲取元素的文本內容 tableI = driver.find_element_by_tag_name('tableData').text #循環測試 list_container = driver.find_elements_by_xpath("//div[@class='list-container mb-bg']/dl/dt/h3/a") for title in list_container: print 'Num' + str(SUMRESOURCES +1) print u'標題: ' + title.text print u'鏈接: ' + title.get_attribute('href') driver.quit()
能輸出網頁源碼,說明安裝成功
示例二:
通過這兩者來解決客戶端重定向問題的例子:
程序首先加載了driver對象,然后請求網站,之后沒0.5秒檢測網站的html元素,如果html元素發生改變則認為頁面發生了重定向,然后打印重定向后的頁面內容。
代碼:
from selenium import webdriver import time from selenium.webdriver.remote.webelement import WebElement from selenium.common.exceptions import StaleElementReferenceException # 處理重定向,可以定時檢查頁面的某元素 # 如果和先前的不一致則可認為客戶端重定向 def wait_for_load(driver): #elem = driver.find_element_by_tag_name("html") title = driver.find_element_by_tag_name("title") #print(title) count = 0 while True: count += 1 if count > 20: print("Timing out after 10 seconds and returning") return time.sleep(.5) newtitle = driver.find_element_by_tag_name("title") if newtitle != title: return #try: # elem = driver.find_element_by_tag_name("html") #except StaleElementReferenceException: # return driver = webdriver.PhantomJS(executable_path='./phantomjs') driver.get("http://pythonscraping.com/pages/javascript/redirectDemo1.html") wait_for_load(driver) print(driver.page_source)
示例三:
import requests from bs4 import BeautifulSoup from selenium import webdriver def getData(dataUrl): #獲取ajax返回的頁面(用bs4獲取不到ajax返回的數據) driver = webdriver.PhantomJS() driver.get(dataUrl) #獲取table元素 tables = driver.find_elements_by_tag_name('table') if tables is None: print('網頁加載獲取數據失敗') logger.info('網頁加載獲取數據失敗') #獲取table元素中的tr元素 trList = tables[0].find_elements_by_tag_name('tr') if trList is None: print('網頁加載獲取數據失敗') logger.info('網頁加載獲取數據失敗') for i in range(0,len(trList)): if i > 0: #獲取table元素中的tr元素中的td元素 tdList = trList[i].find_elements_by_tag_name('td') if tdList is not None: for n in range(0,len(tdList)): #獲取td元素文本內容 print(">>>>%s:%s"%(n,tdList[n].text)) driver.quit() def getDataUrl(issueid): dataUrl = '' url = "http://******/Scsj_tjyb_issue.jsp" headerDict = {'Host': '******', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.31 Safari/537.36', 'Accept': '*/*', 'Accept-Language': 'zh-CN,zh;q=0.8', 'Accept-Encoding': 'gzip, deflate', 'Origin':'http://******, 'Referer': 'http://******/tjyb_front/', 'Connection': 'keep-alive'} data = {'AJAX': '1', 'TEMPLATE_ID': '1114', 'ISSUEID': issueid, 'CATALOGTYPE': 'main', 'LANGUAGE': 'zh', 'HEAD': ''} res = requests.post(url, data=data, headers=headerDict) # 獲取跳轉后的頁面源碼,返回json串 soup = BeautifulSoup(res.content, "html.parser") if soup.find_all('a',target='_blank') is not None: for a_url in soup.find_all('a',target='_blank'): if a_url.string == '******統計表': dataUrl=a_url['href'] break else: print("未獲取到a標簽") logger.info("未獲取到a標簽") print('http://******'+dataUrl) return 'http://******'+dataUrl if __name__ == '__main__': url = getDataUrl('897') getData(url)
示例四:
#自定義請求頭head from selenium import webdriver from selenium.webdriver.common.desired_capabilities import DesiredCapabilities #設置自定義請求頭參數 def get_headers_driver(): desire = DesiredCapabilities.PHANTOMJS.copy() headers = {'Accept': '*/*', 'Accept-Language': 'en-US,en;q=0.8', 'Cache-Control': 'max-age=0', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36', 'Connection': 'keep-alive', 'Referer': 'http://www.baidu.com/' } for key, value in headers.items(): desire['phantomjs.page.customHeaders.{}'.format(key)] = value driver = webdriver.PhantomJS(desired_capabilities=desire, service_args=['--load-images=yes'])#將yes改成no可以讓瀏覽器不加載圖片 return driver # 登錄 def login(): driver = get_headers_driver(cookie) url = "http://******/login/main.do" driver.get(url) #獲取網頁源碼 print(driver.page_source)
注:模擬回車鍵代碼
# 模擬回車
from selenium.webdriver.common.keys import Keys
driver.find_element_by_xpath("**").send_keys(Keys.ENTER)