准備
查看淘寶的頁面是不是靜態頁面,結果是靜態頁面。
想要抓取的是淘寶搜索某個商品的信息,所以要找到淘寶的搜索接口,經過觀察可以看到接口可以這樣解決:
word = '書包'
url = 'https://s.taobao.com/search?q=' + word
其實抓取淘寶主要是想加強自己對正則表達式的理解與運用的,於是決定用requests+re來完成此次練習。
調試
抓取網頁
調試的第一步獲取網頁的源代碼就遇到了問題,真是不幸。於是開始痛苦的調試過程:
- 在頭部信息中添加瀏覽器信息
結果:失敗 - 在頭部信息中添加referer
結果:失敗 - 在頭部信息中添加cookie
結果:返回結果有了變化,於是很高興的去把requests發起的請求改成session會話發起的請求,結果最后發現雖然和以前返回的內容變了,但源代碼還是錯誤的,簡直崩潰,不知道用了什么反爬蟲技術。 - 終極武器----selenium
用這個直接調用真實的瀏覽器對其訪問,終於不會出錯了(這還是要出錯,真的是無fuck可說了),但這個要啟動瀏覽器,速度可能會很慢,所以我把源代碼保存到了本地,避免重復訪問浪費時間。
保存網頁
保存的話用二進制的形式保存,不會出現一些亂七八糟的編碼錯誤,而且用瀏覽器打開的時候可以顯示中文,但用Python讀取的時候,顯示不出來中文,需要解碼才能顯示中文,可能原因是瀏覽器打開文件的時候自動解碼的。
正則表達式查找
把網頁保存到本地后,可以將其讀取保存到一個變量中,然后就可以對其進行操作了。個人感覺對於爬蟲的話,正則表達式最常用的方法應該是findall方法了吧,為了節省時間,可以先把正則表達式編譯,然后再對具體的文本查找。示例:
rst = re.search(r'[1-9]\d{5}', 'bit 100081') #函數式用法:一次性操作
pat = re.compile(r'[1-9]\d{5}') #面向對象用法:編譯后多次操作
rst = pat.search('bit 100081')
正式開始查找的時候,想把價格先找出來,用的是這行代碼:
pat = re.compile(r'.*?<strong.*?>(.*?)</strong>.*?')
可以實現想要的功能。在這過程中遇到兩個問題,一個是\d只能匹配到整數,並不能匹配到有小數點的數,所以換成了.*?;還有一個是正則表達式速度太慢了,雖然只是一個網頁,但是大小有八百多k,也算是幾十萬的內容了,一次匹配竟然要八分鍾,受不了,可能我的正則寫的也不好,但是也掩飾不了它慢的本質了。於是我決定放棄用正則表達式來提取這個網頁的內容。
戰略改變
技術不行,雖然是靜態網頁,但是自己並不能用requests獲取到正確的網頁,只能改用selenium;正則表達式查找太慢,還是用beautifulsoup好。於是從requests+re變成了selenium+beautifulsoup來對網頁進行爬取。
selenium庫調用瀏覽器訪問網頁
比較簡單,幾行代碼搞定對網頁的訪問。需要注意的是,要等待上那么一段時間讓瀏覽器把頁面給加載完成。
try:
browser.get(url)
time.sleep(3)
page = browser.page_source
return page.encode('utf-8').decode('utf-8')
except:
return ''
用bs庫提取信息
對價格信息的提取比較簡單,有唯一的類屬性,可以准確定位到;而對於名稱的定位,類屬性較多,不過也沒啥大礙,全部寫進去就行了。唯一麻煩的是它的名稱是分開的,不過其實其他的東西是假的,其實就在一個標簽的string屬性,至於內容不在一起,其實都是空格,用字符串的strip方法輕松搞定。下面的代碼是定位到所需標簽的父標簽:
price_div = soup.find_all('div', class_='g_price-highlight') #div[0].strong.text
name_div = soup.find_all('div', class_='row row-2 title') #div[0].span.text.strip()
總結
因為對beautifulsoup的使用算是比較熟練的了,所以后面的工作非常順利的完成了。造成最大麻煩就是找不到淘寶的反爬蟲技術到底是什么,技術不夠,有點不爽。
附上源代碼:
from selenium import webdriver
import time
from bs4 import BeautifulSoup
def get_page(url, browser):
try:
browser.get(url)
time.sleep(10)
page = browser.page_source
return page.encode('utf-8').decode('utf-8')
except:
return ''
def parse_page(html):
soup = BeautifulSoup(html, 'html.parser')
return soup
def get_message(soup, glist):
price_div = soup.find_all('div', class_='g_price-highlight') #div[0].strong.text
name_div = soup.find_all('div', class_='row row-2 title') #div[0].span.text.strip()
for i in range(len(price_div)):
glist.append([name_div[i].a.text.strip(), price_div[i].strong.text])
def main():
word = '書包'
url = 'https://s.taobao.com/search?q=' + word #https://s.taobao.com/search?q=%E4%B9%A6%E5%8C%85&s=88
br = webdriver.Chrome()
html = get_page(url, br)
soup = parse_page(html)
glist = []
get_message(soup, glist)
print(glist)
br.close()
main()