使用Selenium+chrome/PhantomJS爬取京東零食。 京東的頁面比較複雜:含有各類請求參數、加密參數,若是直接請求或者分享Ajax的話會很是的繁瑣,Selenium是一個自動化測試工具,能夠驅動瀏覽器完成各類操做:模擬點擊、輸入、下滑等各類功能,如此一來,咱們只須要關心操做,而不須要關心後臺發生了什麼樣的請求。PhantomJS是無界面的瀏覽器,比Selenium方便,phantomJS已經被廢棄了,直接配置Selenium的瀏覽器options就能夠實現無界面瀏覽器(詳情請看文末的實現代碼)。css
本次實戰爬取的是京東搜索「零食」出現的全部內容,解析庫是PyQuery。 ###目標站點分析 分析發現京東搜索「零食」後發起了不少請求,比較複雜。這裏使用Selenium驅動瀏覽器,這能夠屏蔽這些複雜請求的分析,因此須要依次實現:html
Selenium和webdriver安裝可看下以前的文章 (1)實現步驟 java
瀏覽器右鍵->檢查,上圖中的copy選項卡能夠在元素查找時使用,這篇文章中咱們使用css選擇器查找元素,點擊「copy selector」,在查找元素時直接粘貼就能夠了。 在正式寫代碼前須要考慮到:python
(2)網頁解析 web
(3)在真實貼代碼和數據以前,先說明幾個曾經踩過的坑:面試
下面是爬取的數據: 正則表達式
完整源碼和代碼詳細解析chrome
# 京東首頁搜素框
def search(key_words='零食'):
try:
input_text = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#key')))
button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#search > div > div.form > button')))
input_text.send_keys(key_words)
button.click()
total = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#J_topPage > span > i')))
total = int(total.text)
order = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#J_filter > div.f-line.top > div.f-sort > a:nth-child(3)')))
order.click()
except TimeoutException:
print('search 超時')
print('一共', total, '頁')
return total
# 翻頁
def next_page(next_page):
# 翻頁使用的策略是手動輸入頁碼,而後點擊跳轉,可是有個問題就是:
# 不滑動滑塊直接定位頁碼輸入框會出現:找不到該元素的異常,這主要是,頁面未加載形成的
# 也就是:當你在京東上搜索商品的時候,瀏覽器沒有下拉到翻頁那裏時,頁面就不會加載,頁面沒有加載天然找不到對應的元素
# 這也是下面這三條指令的意義所在
# browser.execute_script(js)
try:
browser.execute_script('arguments[0].scrollIntoView()',
browser.find_element_by_css_selector('#footer-2017 > div > div.copyright_info > p:nth-child(1) > a:nth-child(1)'))
time.sleep(2)
# 下滑直到「下一頁」按鈕出現
browser.execute_script('arguments[0].scrollIntoView()',
browser.find_element_by_css_selector('#J_bottomPage > span.p-num > a.pn-next'))
input_text = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#J_bottomPage > span.p-skip > input')))
jump = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#J_bottomPage > span.p-skip > a')))
except TimeoutException:
print('翻頁超時')
input_text.clear()
input_text.send_keys(next_page)
jump.click()
try:
# 等待翻頁完成
wait.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR, '#J_bottomPage > span.p-num > a.curr'), str(next_page)))
browser.execute_script('arguments[0].scrollIntoView()',
browser.find_element_by_css_selector('#J_bottomPage > span.p-num > a.pn-next'))
except TimeoutException:
print('翻頁失敗', next_page)
print('\n')
print('解析第', next_page, '頁商品')
try:
for good in parse_page():
write_to_csv_file(good.values())
except TimeoutException:
print('第', next_page, '頁的第', count_item, '個商品解析時發生超時')
browser.switch_to.window(browser.window_handles[0])
return None
# 頁面數據解析
def parse_page():
global count_item
count_item = 0# 統計每一頁的商品
# 解析頁面前,先將瀏覽器頁面下滑置「下一頁」地方
browser.execute_script('arguments[0].scrollIntoView()',
browser.find_element_by_css_selector('#J_bottomPage > span.p-num > a.pn-next'))
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.m-list .ml-wrap #J_goodsList .gl-item')))
doc = pq(browser.page_source, parser="html")
goods = doc('.m-list .ml-wrap #J_goodsList .gl-item').items()
browser.switch_to.window(browser.window_handles[1])
for good in goods:
count_item = count_item +1
print('當前是第',count_item,'個商品')
detail_herf = good.find('.p-name a').attr('href')
browser.get('http://'+detail_herf)
# 等待商品介紹 評價等數據加載完成
browser.execute_script('arguments[0].scrollIntoView()',
browser.find_element_by_css_selector('.detail #detail .tab-main ul li'))
detail_doc = pq(browser.page_source,parser='html')
# 京東上主要有兩類商品:
# 一類:與商品介紹並列的一共5個標籤
# 第二類:只有商品介紹和評價兩類標籤,
# 下面這個css定位很容易寫錯
ul = list(detail_doc('.detail #detail .tab-main ul li').items())
if len(ul)==5 :
# 商品評價按鈕 五個li標籤,對應第二類商品
#等待評價按鈕加載完成
comments_button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#detail > div.tab-main.large.detail-elevator > ul > li:nth-child(2)')))
comments_button.click() # 點擊「評價」按鈕
rate = wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, '#i-comment > div.rate > strong')))# 等待rate加載完成
rate_comments = rate.text # rate是webElement類型,調用text便可獲取對應的文本,注意不是調用text()
# 等待差評數量加載完成(差評數量加載完了也就意味着好評和中評數量加載完了)
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#comments-list > div.mt > div > ul > li:nth-child(4) > a > em')))
tmp_doc = pq(browser.page_source, parser='html')
comments_obtain = tmp_doc('#comments-list .mt-inner ul li').items()# 獲取評論數量
index = 0
for comment in comments_obtain:
if index == 1:
good_comments = comment('a em').text()[1:-1]
elif index == 2:
neutral_comments = comment('a em').text()[1:-1]
elif index == 3:
bad_comments = comment('a em').text()[1:-1]
break
index = index + 1
yield {
'name': good.find('.p-name a em').text().strip().replace('\n', ' '),
'price': good.find('.p-price i').text(),
'total_comments': good.find('.p-commit a').text(),
'good_comments': good_comments,
'neutral_comments': neutral_comments,
'bad_comments': bad_comments,
'good_rate': rate_comments
}
elif len(ul)==7 :# 對應第二類商品
comments_button = wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR, '#detail > div.tab-main.large > ul > li:nth-child(5)')))
comments_button.click()#點擊「評價」按鈕
rate = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#comment > div.mc > div.comment-info.J-comment-info > div.comment-percent > div')))
rate_comments = rate.text# rate是webElement類型,調用text便可獲取對應的文本,注意不是調用text()
# 等待差評數量加載完成(差評數量加載完了也就意味着好評和中評數量加載完了)
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#comment > div.mc > div.J-comments-list.comments-list.ETab > div.tab-main.small > ul > li:nth-child(7) > a > em')))
tmp_doc = pq(browser.page_source,parser='html')
comments_obtain = tmp_doc('.tab-main .filter-list li' ).items()
index = 0
for comment in comments_obtain:
if index==4:
good_comments = comment('a em').text()[1:-1]
elif index==5:
neutral_comments = comment('a em').text()[1:-1]
elif index==6:
bad_comments = comment('a em').text()[1:-1]
break
index = index + 1
yield {
'name': good.find('.p-name a em').text().strip().replace('\n', ' '),
'price': good.find('.p-price i').text(),
'total_comments': good.find('.p-commit a').text(),
'good_comments':good_comments,
'neutral_comments':neutral_comments,
'bad_comments':bad_comments,
'good_rate': rate_comments
}
browser.switch_to.window(browser.window_handles[0])
複製代碼
java學習筆記、10T資料、100多個java項目分享瀏覽器
歡迎關注我的公衆號【菜鳥名企夢】,公衆號專一:互聯網求職面經、java、python、爬蟲、大數據等技術分享**: 公衆號**菜鳥名企夢
後臺發送「csdn」便可免費領取【csdn】和【百度文庫】下載服務; 公衆號菜鳥名企夢
後臺發送「資料」:便可領取5T精品學習資料**、java面試考點和java面經總結,以及幾十個java、大數據項目,資料很全,你想找的幾乎都有 框架