1. 程式人生 > >【Python3 爬蟲學習筆記】動態渲染頁面爬取 4 —— 使用Selenium爬取淘寶商品

【Python3 爬蟲學習筆記】動態渲染頁面爬取 4 —— 使用Selenium爬取淘寶商品

並不是所有頁面都可以通過分析Ajax來完成抓取。比如,淘寶,它的整個頁面資料確實也是通過Ajax獲取的,但是這些Ajax介面引數比較複雜,可能會包含加密祕鑰等,所以如果想自己構造Ajax引數,還是比較困難的。對於這種頁面,最方便快捷的抓取方法就是通過Selenium。我們利用Selenium來模擬瀏覽器操作,抓取淘寶的商品資訊,並將結果儲存到MongoDB。 我們實現如下抓取列表頁的方法:

from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.
common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait from urllib.parse import quote browser = webdriver.Chrome() wait = WebDriverWait(browser, 10) KEYWORD = 'iPad' def index_page(page): """ 抓取索引頁 :param page:頁碼 """
print('正在爬取第', page, '頁') try: url = 'https://s.taobao.com/search?q=' + quote(KEYWORD) browser.get(url) if page > 1: input = wait.until(EC.presence_of_located((By.CSS_SELECTOR, '#mainsrp-pager div.form > input'))) submit = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#mainsrp-pager div.form > span.btn.J_Submit'
))) input.clear() input.send_keys(page) submit.click() wait.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR, '#mainsrp-pager li.item.active > span'), str(page))) wait.until(EC.presence_of_element_located((By.CSS_ELECTOR, '.m-itemlist .items .item'))) get_products() except TimeoutException: index_page(page)

這裡首先構造了一個WebDriver物件,使用的瀏覽器時Chrome,然後指定一個關鍵詞,如iPad,接著定義了index_page()方法,用於抓取商品列表頁。 在該方法裡,我們首先訪問了搜尋商品的連結,然後判斷了當前的頁碼,如果大於1,就進行跳頁操作,否則等待頁碼載入完成。 等待載入時,我們使用了WebDriverWait物件,它可以指定等待條件,同時指定一個最長等待時間,這裡指定為最長10秒。如果在這個時間內成功匹配了等待條件,也就是說頁面元素成功加載出來了,就立即返回相應結果並繼續向下執行,否則到了最大等待時間還沒有加載出來時,就直接丟擲異常。 比如,我們最終要等待商品資訊加載出來,就指定了presence_of_element_located這個條件,然後傳入了.m-itemlist .items .item這個選擇器,而這個選擇器對應的頁面內容就是每個商品的資訊塊,可以到頁面裡面檢視一下。如果載入成功,就會執行後續的get_products()方法,提取商品資訊。 關於翻頁操作,這裡首先獲取頁碼輸入框,賦值為input,然後獲取“確定”按鈕,賦值為submit。 首先,我們清空了輸入框,此時呼叫clear()方法即可。隨後,呼叫send_keys()方法將頁碼填充到輸入框中,然後點選“確認”按鈕即可。 我們需要判斷當前高亮的頁碼數是當前的頁碼數即可,所以這裡使用了另一個等待條件text_to_be_present_in_element,它會等待指定的文字出現在某一個節點裡面即返回成功。這裡我們將高亮的頁碼節點對應的CSS選擇器和當前要跳轉的頁碼通過引數傳遞給這個等待條件,這樣它就會檢測當前高亮的頁碼節點是不是我們傳過來的頁碼數,如果是,就證明頁面成功跳轉到了這一頁,頁面跳轉成功。 這樣剛才實現的index_page()方法就可以傳入對應的頁碼,待加載出對應的頁碼的商品列表後,在去呼叫get_products()方法進行頁面解析。

解析商品列表

接下來,我們就可以實現get_products()方法來解析商品列表了。這裡我們直接獲取頁面原始碼,然後用pyquery進行解析,實現如下:

def get_products():
	"""
	提取商品資料
	"""
	html = browser.page_source
	doc = pq(html)
	items = doc('#mainsrp-itemlist .items .item').items()
	for item in items:
		product = {
			'image':item.find('.pic .img').attr('data-src'),
			'price':item.find('.price').text(),
			'deal':item.find('.deal-cnt').text(),
			'title':item.find('.title').text(),
			'shop':item.find('.shop').text(),
			'location':item.find('.location').text()
		}
		print(product)
		save_to_mongo(product)

首先,呼叫page_source屬性獲取頁碼的原始碼,然後構造了PyQuery解析物件,接著提取了商品列表,此時使用的CSS選擇器是#mainsrp-itemlist .items .item,它會匹配整個頁面的每個商品。它的匹配結果是多個,所以這裡我們又對它進行了一次遍歷,用for迴圈將每個結果分別進行解析,每次迴圈把它賦值為item遍歷,每個item變數都是一個PyQuery物件,然後再呼叫它的find()方法,傳入CSS選擇器,就可以獲取單個商品的特定內容了。 我們需要先利用find()方法找到圖片的這個節點,然後再呼叫attr()方法獲取商品的data-src屬性,這樣就成功提取了商品圖片連結。然後用同樣的方法提取商品的價格、成交量、名稱、店鋪和店鋪所在地等資訊,接著將所有提取結果賦值為一個字典product,隨後呼叫save_to_mongo()將其儲存到MongoDB即可。

儲存到MongoDB

接下來,我們將商品資訊儲存到MongoDB,實現程式碼如下:

MONGO_URL = 'localhost'
MONGO_DB = 'taobao'
MONGO_COLLECTION = 'products'
client = pymongo.Mongo(MONGO_URL)
db = client[MONGO_DB]
def save_to_mongo(result):
	"""
	儲存至MongoDB
	:param result:結果
	"""
	try:
		if db[MONGO_COLLECTION].insert(result):
			print('儲存到MongoDB成功')
	except Exception:
		print('儲存到MongoDB失敗')

這裡首先建立了一個MongoDB的連線物件,然後指定了資料庫,隨後指定了Collection的名稱,接著直接呼叫insert()方法將資料插入到MongoDB。此處的result變數就是在get_products()方法裡傳來的product,包含單個商品的資訊。

遍歷每頁

剛才我們所定義的get_index()方法需要接收引數page,page代表頁碼。這裡我們實現頁碼遍歷即可,程式碼如下:

MAX_PAGE = 100
def main():
	"""
	遍歷每一頁
	"""
	for i in range(1, MAX_PAGE + 1):
		index_page(i)

這裡定義最大的頁碼數為100,range()方法的返回結果就是1到100的列表,順序遍歷,呼叫index_page()即可。