更新
其實本文的初衷是為了獲取淘寶的非匿名旺旺,在淘寶詳情頁的最下方有相關評論,含有非匿名旺旺號,快一年了淘寶都沒有修復這個。
可就在今天,淘寶把所有的賬號設置成了匿名顯示,SO,獲取非匿名旺旺號已經不可能了。那本節就帶大家抓取匿名旺旺號熟悉一下Selenium吧。
2016/7/1
前言
嗯,淘寶,它一直是個難搞的家伙。
而且買家在買寶貝的時候大多數都是匿名評論的,大家都知道非匿名評論是非常有用的,比如對於大數據分析,分析某個寶貝的購買用戶星級狀況等等。
現在已經不能獲取非匿名了,此句已沒有意義了。
對於抓淘寶,相信嘗試過的童鞋都能體會到抓取它到艱辛,最簡單的方法莫過於模擬瀏覽器了,本節我們就講解一下利用 Selenium 抓取淘寶評論的方法。
項目提供了如下功能:
- 輸入淘寶關鍵字采集淘寶鏈接並寫入到文件
- 從文件讀取鏈接,執行評論采集
- 將評論和旺旺號保存到Excel中
- 記錄當前采集鏈接索引,保存進度
准備工作
在開始本節之前
你需要了解一些基礎知識,我們需要用到 Selenium 這個東西,詳情請看
我們首先講解一下你需要做怎樣的配置。
首先你需要安裝 Python,版本是2.7
然后需要安裝的 Python 類庫。
1
|
pip install pyquery selenium twisted requests xlrd xlwt xlutils
|
安裝瀏覽器 Chrome,安裝瀏覽器 Chrome,安裝瀏覽器Chrome。
然后下載ChromeDriver,ChromeDriver是驅動瀏覽器的工具,需要把它配置到環境變量里。
有的童鞋說,為什么不用 PhantomJS,因為為了防止淘寶禁掉我們,需要登錄淘寶賬號,登錄過程可能會出現奇奇怪怪得驗證碼,滾動條,手機驗證,如果用 PhantomJS 的話不方便操作,所以在這里我們就使用 Chrome 了。
上面是 ChromeDriver 的下載地址,谷歌都上得了,這個不在話下吧,這是最官方的版本,其他鏈接請自行搜索。
找到對應平台的 ChromeDriver,解壓后將可執行文件配置到環境變量里,配置到環境變量里,配置到環境變量里!重要的話說三遍。
流程簡述
首先我們拿一個例子來演示一下全過程。
隨意打開天貓一個鏈接
我們首先觀察一下評論,可以發現所有的評論都是匿名的。即使這個用戶不是匿名評論的,那也會顯示匿名,淘寶這保密做的挺好。
心機的淘寶啊,那我們如果想獲取一些旺旺號該咋辦?
接下來我們返回寶貝詳情頁面,然后一直下拉下拉,拉到最最后,可以看到有個“看了又看”板塊。
有沒有!!發現了新大陸,這是什么?這是此寶貝相關寶貝以及它的一些評論。
看到了有非匿名用戶了,哈哈哈,淘寶加密了評論,推薦部分卻沒有加密。
嗯,就從這里,我們把它們的旺旺號都抓下來,順便把評論和購買的寶貝抓下來。
現在已經全部改成了匿名,上述話已經無意義了。
那么抓取完之后,保存到哪里呢?為了便於管理和統計,在這里保存到 Excel 中,那么就需要用到 xlrd, xlwt, xlutils 等庫。
嗯,動機就是這樣。
實戰爬取
抓取過程
首先我們觀察這個鏈接,在最初的時候,其實網頁並沒有加載最下方的“看了又看”內容的,慢慢往下滑動網頁,滑到最下方之后,才發現看了又看頁面才慢慢加載出來。
很明顯,這個地方使用了Ajax,由於我們用的是 Selenium,所以這里我們不能直接來模擬 Ajax 的 Request,需要我們來模擬真實的用戶操作。
所以我們要模擬的就是,在網頁部分加載出來之后,模擬瀏覽器滑動到下方,使“看了又看”內容顯示出來,然后獲取網頁源代碼,解析之即可。
那么在這里就出現了兩個至關重要的點,一個是判斷網頁框架大體加載出來,另一個是模擬滑動直到最下方的內容加載出來。
首先,我們解決第一個問題,怎樣判斷網頁框架大體加載出來。我們可以用網頁中的某個元素的出現與否來判斷。
比如
這一部分是否加載出來。
審查一下代碼,ID叫做 J_TabBarBox,好,那就用它來作為網頁初步加載成功的標志。
在 Selenium 中,我們用顯式等待的方法來判斷該元素是否已經加載成功。
1
2
3
4
5
6
7
8
9
10
|
try:
driver.get(url)
WebDriverWait(driver, timeout).until(
EC.presence_of_element_located((By.ID, "J_TabBarBox"))
)
except TimeoutException:
return False
if is_recommends_appear(driver, max_scroll_time):
print u'已經成功加載出下方櫥窗推薦寶貝信息'
return driver.page_source
|
接下來我們需要模擬下拉瀏覽器,不妨直接下拉到底部,再從底部向上拉,可能需要下拉多次,所以在這里定義了一個下拉次數,那么判斷“看了又看”正文內容是否出現依然可以用顯式等待的方法。
瀏覽器審查元素發現它的選擇器是 #J_TjWaterfall li
那么可以用如下方法來判斷是否加載成功
1
2
3
4
5
|
try:
driver.find_element_by_css_selector('#J_TjWaterfall li')
except NoSuchElementException:
return False
return True
|
下拉過程可以用執行 JavaScript 的方法實現。
1
2
|
js = "window.scrollTo(0,document.body.scrollHeight-" + str(count * count* 200) + ")"
driver.execute_script(js)
|
其中 count 是下拉的次數,經過測試之后,每次拉動距離和 count 是平方關系比較科學,具體不再描述,當然你可以改成自己想要的數值。
嗯,加載出來之后,就可以用
1
|
driver.page_source
|
來獲取網頁源代碼了
用 pyquery 解析即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
doc = pq(html)
items = doc('#J_TjWaterfall > li')
print u'分析得到下方寶貝中的用戶評論:'
for item in items.items():
url = item.find('a').attr('href')
if not url.startswith('http'):
url = 'https:' + url
comments_info = []
comments = item.find('p').items()
for comment in comments:
comment_user = comment.find('b').remove().text()
comment_content = comment.text()
anonymous_str = config.ANONYMOUS_STR
<del>if not anonymous_str in comment_user:</del> #此句本來用來判斷是否匿名,現淘寶已修復該漏洞,只能抓取全部匿名的了
comments_info.append((comment_content, comment_user))
info.append({'url': url, 'comments_info': comments_info})
return info
|
然后保存到 Excel 中。
運行結果截圖
可以發現,另外提供了先登陸后爬取的功能,然后保存了爬取進度。
采集鏈接
剛才我們測試的鏈接是哪里來的?我們不能一個個去找吧?所以,在這里又提供了一個采集鏈接的過程,將采集的鏈接保存到文本,然后抓取的時候從文本讀取一個個鏈接即可。
所以在這里我們模擬搜索的過程,關鍵字讓用戶輸入,將搜索的鏈接采集下來。
在此 Selenium 模擬了輸入文字,點擊按鈕和翻頁的功能。
核心代碼如下
下面的方法模擬了加載出搜索框之后輸入文字點擊回車的過程,將網頁的結果返回。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
def get_results(keyword):
driver = config.DRIVER
link = config.SEARCH_LINK
driver.get(link)
try:
WebDriverWait(driver, config.TIMEOUT).until(
EC.presence_of_element_located((By.ID, "mq"))
)
except TimeoutException:
print u'加載頁面失敗'
try:
element = driver.find_element_by_css_selector('#mq')
print u'成功找到了搜索框'
keyword = keyword.decode('utf-8', 'ignore')
print keyword
print u'輸入關鍵字', keyword
for word in keyword:
print word
element.send_keys(word)
element.send_keys(Keys.ENTER)
except NoSuchElementException:
print u'沒有找到搜索框'
print u'正在查詢該關鍵字'
try:
WebDriverWait(driver, config.TIMEOUT).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "#J_ItemList div.productImg-wrap"))
)
except TimeoutException:
print u'查詢失敗'
html = driver.page_source
return html
|
下面的方法模擬了翻頁的過程,到指定的翻頁數目為止
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
def get_more_link():
print u'正在采集下一頁的寶貝鏈接'
driver = config.DRIVER
try:
js = "window.scrollTo(0,document.body.scrollHeight)"
driver.execute_script(js)
except WebDriverException:
print u'頁面下拉失敗'
try:
next = driver.find_element_by_css_selector('#content b.ui-page-num > a.ui-page-next')
next.click()
except NoSuchElementException:
print u'找到了翻頁按鈕'
driver.implicitly_wait(5)
try:
WebDriverWait(driver, config.TIMEOUT).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "#J_ItemList div.productImg-wrap"))
)
except TimeoutException:
print u'查詢失敗'
html = driver.page_source
parse_html(html)
|
運行結果截圖
采集到到內容保存到 urls.txt 中
嗯,這下采集鏈接和爬取鏈接都有了。
代碼放送
扯了這么多,許多童鞋已經蠢蠢欲動了,大聲告訴我你們想要的是什么?
哦沒錯!代碼!
嗯在這呢!
附加扯淡
嗯想說一句,在這里還提供了一些可配置項,比如翻頁最大次數,超時時間,下拉次數,登錄鏈接等等。
都可以在 config.py 中配置。
- URLS_FILE
保存鏈接單的文件
- OUT_FILE
輸出文本EXCEL路徑
- COUNT_TXT
計數文件
- DRIVER
瀏覽器驅動
- TIMEOUT
采集超時時間
- MAX_SCROLL_TIME
下拉滾動條最大次數
- NOW_URL_COUNT
當前采集到第幾個鏈接
- LOGIN_URL
登錄淘寶的鏈接
- SEARCH_LINK
采集淘寶鏈接搜索頁面
- CONTENT
采集鏈接臨時變量
- PAGE
采集淘寶鏈接翻頁數目
- FILTER_SHOP
是否過濾相同店鋪
ANONYMOUS_STR
匿名用戶標志,已失效
哦,對了,程序怎么用啊?看 README!