通過前文爬蟲理論結合實戰的部分我們對爬蟲有了初步的瞭解,首先通過requests模擬瀏覽器進行請求,接着通過正則表達式或者解析庫對網頁進行解析,還知道了動態網頁Ajax的爬取方法,但總是擔心模擬不夠會被反爬偵測出來,而本文要介紹的方法則是直接調用瀏覽器的方式進行高仿瀏覽器爬蟲,這樣就再也不用擔心啦~
目錄
一、Selenium庫介紹
1.Selenium簡介
selenium 是一套完整的web應用程序測試系統,包含了測試的錄製(selenium IDE),編寫及運行(Selenium Remote Control)和測試的並行處理(Selenium Grid)。Selenium的核心Selenium Core基於JsUnit,完全由JavaScript編寫,因此可以用於任何支持JavaScript的瀏覽器上。
2.Selenium安裝
Selenium的安裝可以使用如下命令:
pip install selenium
還沒完!由於我們推薦chrome谷歌瀏覽器作爲模擬瀏覽器,因此我們還需要chromedriver作爲驅動,相應版本選擇需要查看谷歌瀏覽器版本,在chrome瀏覽器上方地址欄輸入:
chrome://settings/help
作者chrome瀏覽器版本爲80.0.2987.132,通過此版本號進入chrome-driver鏡像地址:http://npm.taobao.org/mirrors/chromedriver/ 找到並下載放入anaconda根目錄(即與python.exe同目錄下面):
3.Selenium使用
如果想要聲明並調用瀏覽器則需要:
# 通過selenium導入webdriver方法
from selenium import webdriver
# 通過webdriver方法調用谷歌瀏覽器驅動
browser = webdriver.Chrome()
訪問頁面:
url = 'https:www.baidu.com'
#打開瀏覽器預設網址
browser.get(url)
#打印網頁源代碼
print(browser.page_source)
#關閉瀏覽器
browser.close()
查找元素,此處列舉下常用查找元素方法:
-
find_element_by_name
-
find_element_by_id
-
find_element_by_xpath
-
find_element_by_link_text
-
find_element_by_partial_link_text
-
find_element_by_tag_name
-
find_element_by_class_name
-
find_element_by_css_selector
url = 'https:www.taobao.com'
#打開瀏覽器預設網址
browser.get(url)
# 通過
input_first = browser.find_element_by_id('q')
input_two = browser.find_element_by_css_selector('#q')
print(input_first)
print(input_two)
交互動作:
from selenium import webdriver
# 導入交互動作模塊
from selenium.webdriver import ActionChains
browser = webdriver.Chrome()
url = "http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable"
browser.get(url)
browser.switch_to.frame('iframeResult')
source = browser.find_element_by_css_selector('#draggable')
target = browser.find_element_by_css_selector('#droppable')
actions = ActionChains(browser)
actions.drag_and_drop(source, target)
actions.perform()
獲取ID,位置,標籤名:
from selenium import webdriver
browser = webdriver.Chrome()
# 知乎探索頁
url = 'https://www.zhihu.com/explore'
browser.get(url)
# 通過css選擇器查找標籤
input = browser.find_element_by_css_selector('.zu-top-add-question')
print(input.id)
print(input.location)
print(input.tag_name)
print(input.size)
二、京東商品爬蟲實戰
1.京東網頁分析與獲取
首先確定想要爬取的商品,此處我們假定要爬取京東關鍵字爲“電腦”的所有商品信息,先登錄京東界面並在搜索框中輸入“電腦”,之後將鏈接複製。
我們需要爬取的是這樣的一個頁面,包含電腦相關信息,並且還要進行翻頁爬取,這裏我們將直接採用Selenium庫模擬谷歌瀏覽器進行操作。爬蟲的基本思路爲:利用程序模擬瀏覽器自動打開網頁,然後以上文鏈接作爲起始頁打開,等到頁面加載完畢後,爬取這一頁的數據,然後模擬鼠標點擊下一頁,等下一頁加載完畢後再次爬取數據。
首先導入庫:
import csv
import json
import time
import random
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import selenium.common.exceptions
之後通過調用webdriver的的chrome方法控制chrome瀏覽器並設置等待,
start_url = 'https://search.jd.com/Search?keyword=%E7%94%B5%E8%84%91&enc=utf-8&pvid=fc7e43c13ba3462ca2cfbbbc71781862'
browser = webdriver.Chrome()
browser.implicitly_wait(10)
wait = WebDriverWait(browser,10)
2.網頁信息提取
通過Selenium庫內置的Xpath解析方法和css選擇器將商品價格、名稱、評論提取出來:
prices = wait.until(EC.presence_of_all_elements_located((By.XPATH,'//div[@class="gl-i-wrap"]/div[2]/strong/i')))
names = wait.until(EC.presence_of_all_elements_located((By.XPATH,'//div[@class="gl-i-wrap"]/div[3]/a/em')))
commits = wait.until(EC.presence_of_all_elements_located((By.XPATH,'//div[@class="gl-i-wrap"]/div[4]/strong')))
3.網頁信息存儲
本文設置兩種存儲方式,json和csv:
if file_format=='json' :
for i in range(60):
count += 1
print('寫入數據:'+str(count))
item = {}
item['price'] = prices[i].text
item['name'] = names[i].text
item['commit'] = commits[i].text
json.dump(item,file,ensure_ascii = False)
elif file_format=='csv' :
for i in range(60):
count += 1
print('寫入數據:'+str(count))
item = {}
item['price'] = prices[i].text
item['name'] = names[i].text
item['commit'] = commits[i].text
for key in item:
writer.writerow([key, item[key]])
4.自動化爬蟲構建
定義模擬翻頁程序:
def turn_page(self):
try:
self.wait.until(EC.element_to_be_clickable((By.XPATH,'//a[@class="pn-next"]'))).click()
self.browser.execute_script("window.scrollTo(0,document.body.scrollHeight)")
time.sleep(3)
except selenium.common.exceptions.NoSuchElementException:
return True
except selenium.common.exceptions.TimeoutException:
print('turn_page:TimeoutException')
self.page_turning()
except selenium.common.exceptions.StaleElementReferenceException:
print('turn_page:StaleElementReferenceException')
self.browser.refresh()
else:
return False
綜上,我們將整個爬蟲程序寫入JditemSpider類,同時將存儲文件形式寫入類的構造方法,在類中依次定義parse_page方法用於解析單頁網頁,write2file方法將數據增量寫入csv文件或json文件中,turn_page方法定義翻頁,close方法在爬蟲結束之後自動關閉瀏覽器,crawl方法爲京東商品自動化行爲,整個JditemSpider面向對象類結構如下,可進一步加入異常處理:
class JditemSpider():
def init(self):
self.file_format = 'csv'
while self.file_format!='json' and self.file_format!='csv':
self.file_format = input('請選擇[json] [csv]中的一種輸入')
if self.file_format=='json' :
self.file = open('jd_item.json','w',encoding='utf-8')
elif self.file_format=='csv' :
self.file = open('jd_item.csv','w',encoding='utf-8',newline='')
self.writer = csv.writer(self.file)
print('File Initialized')
self.prices = []
self.names = []
self.commits = []
self.count = 0
self.start_url = 'https://search.jd.com/Search?keyword=%E7%94%B5%E8%84%91&enc=utf-8&pvid=fc7e43c13ba3462ca2cfbbbc71781862'
print('Data Initialized')
self.browser = webdriver.Chrome()
self.browser.implicitly_wait(10)
self.wait = WebDriverWait(self.browser,10)
print('Browser Initialized')
def parse_page(self):
self.prices = self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//div[@class="gl-i-wrap"]/div[2]/strong/i')))
self.names = self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//div[@class="gl-i-wrap"]/div[3]/a/em')))
self.commits = self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//div[@class="gl-i-wrap"]/div[4]/strong')))
def write2file(self):
if self.file_format=='json' :
for i in range(60):
self.count += 1
print('寫入數據:'+str(self.count))
item = {}
item['price'] = self.prices[i].text
item['name'] = self.names[i].text
item['commit'] = self.commits[i].text
json.dump(item,self.file,ensure_ascii = False)
elif self.file_format=='csv' :
for i in range(60):
self.count += 1
print('寫入數據:'+str(self.count))
item = {}
item['price'] = self.prices[i].text
item['name'] = self.names[i].text
item['commit'] = self.commits[i].text
for key in item:
self.writer.writerow([key, item[key]])
def turn_page(self):
self.wait.until(EC.element_to_be_clickable((By.XPATH,'//a[@class="pn-next"]'))).click()
self.browser.execute_script("window.scrollTo(0,document.body.scrollHeight)")
time.sleep(3)
def close(self):
self.browser.quit()
print('Finished')
def crawl(self):
self.init()
self.browser.get(self.start_url)
self.browser.execute_script("window.scrollTo(0,document.body.scrollHeight)")
while True:
self.parse_page()
self.write2file()
if self.turn_page()==True :
break
self.close()
至此利用Selenium庫模擬瀏覽器爬取京東動態網頁的爬蟲構建完成,再通過此爬蟲總結一下:首先我們通過瀏覽網頁結構獲取網頁起始頁,並通過webdriver方法調起谷歌瀏覽器,然後通過xpath解析方法獲取當前頁面所想獲取到的信息並存爲csv,之後通過模擬瀏覽器翻頁行爲進行自動化翻頁,從而建立起整個循環爬蟲結構,最後將其封裝爲一個JditemSpyder類,通過調用此類的crawl方法即可完成自動化爬取。結果如下:
爬蟲完整代碼可以在公衆號中回覆“京東”獲得。下文將進一步對手機app抓包爬蟲進行講解和實戰,前文涉及的基礎知識可參考下面鏈接:
學習號,涉及數據分析與挖掘、數據結構與算法、大數據組件及機器學習等內容