站點分析
- 看了交互,好複雜
- 看了下Ajax,好複雜
- 看了下其餘內容,看不懂...
因此,沒啥好分析的,直接上selenium吧html
源碼及遇到的問題
在搜索時,會跳轉到登陸界面
這個沒有辦法,是淘寶的反爬蟲機制. 由於經過selenium webdriver調用的瀏覽器會有不少異於正常瀏覽器的參數,具體生成了啥參數,咱也沒看懂.
具體的能夠參考下面這個大姐的文章python
分析淘寶登錄對selenium爬蟲的封殺方案,反爬蟲機制的升級git
並且阿里不愧是阿里,哪怕webdriver調用的chrome中輸入用戶名和密碼依舊不能夠.github
網上查了一下,基本是selenium是被封的死死的,基本上比較靠譜的方法就是使用pyppeteer
庫.
那麼問題來了...web
- 我此次就是玩selenium的,臨陣換庫,很差.
- 懶
- 懶
- 懶
好了,總結了這麼多,最終,發現了淘寶的一個bug. 雖然用戶名密碼登陸的方式會因爲ua值校驗等問題被拒絕. 可是掃碼登陸不會...chrome
因此個人解決思路很土,先掃碼登陸,拿到cookie,而後調用chrome以前,先把cookie寫進去. (注意!這裏有個坑,很大的坑) 若是不出意外的話,應該是能夠的.數據庫
step1:幹起來! 先取cookie
- def get_taobao_cookies():
- url = 'https://www.taobao.com/'
- browser.get('https://login.taobao.com/')
- while True:
- print("please login to Taobao!")
-
- time.sleep(4)
-
- while browser.current_url == url:
- tbCookies = browser.get_cookies()
- browser.quit()
- output_path = open('taobaoCookies.pickle', 'wb')
- pickle.dump(tbCookies, output_path)
- output_path.close()
- return tbCookies
-
知識補充:pickle模塊數組
python的pickle模塊實現了基本的數據序列和反序列化。
經過pickle模塊的序列化操做咱們可以將程序中運行的對象信息保存到文件中去,永久存儲。
經過pickle模塊的反序列化操做,咱們可以從文件中建立上一次程序保存的對象。
基本接口:
pickle.dump(obj, file, [,protocol])
有了 pickle 這個對象, 就能對 file 以讀取的形式打開:
x = pickle.load(file)
瀏覽器
取cookie卻是沒什麼問題. 問題是,這是我第一次見到原始的cookie,有點懵. 仔細看了以後才搞懂:微信
- 取出的cookie是一個數組
- 數組的每一個元素是一個cookie
- 每一個cookie又是一個字典,其中記錄這這個cookie的 domian,key,value,path等等屬性.
這裏我用pickle.dump()方法把cookie存儲下來了. 下次使用的時候,直接load一下就行了.
step2:載入cookie
載入的話分爲兩部分:
第一部分:從文件中讀取cookie
這個很簡單,不作過多描述
- def read_taobao_cookies():
- if os.path.exists('taobaoCookies.pickle'):
- read_path = open('taobaoCookies.pickle', 'rb')
- tbCookies = pickle.load(read_path)
- else:
- tbCookies = get_taobao_cookies()
- return tbCookies
-
第二部分:講cookie載入chrome
這個可把我坑慘了.
先看代碼,在search()方法中定義瞭如何載入cookie
- cookies = read_taobao_cookies()
-
- browser.get('https://www.taobao.com')
- for cookie in cookies:
-
- if 'expiry' in cookie:
- del cookie['expiry']
- browser.add_cookie(cookie)
-
這裏須要注意的有兩點:
- 在調用add_cookie()方法以前,必須先打開一個網頁.否則的話就會報
InvalidCookieDomainException
的錯誤.
- cookie中的'expiry'屬性要刪除,否則會報
invalid argument: invalid 'expiry'
可是看了下API,add_cookie()是支持這個expiry這個參數的
後來查了一下,當前chromedriver對於expiry只支持int64,不支持double. 聽說是chromedriver的一個bug,在後續版本中會修復.
詳細回答參見這個問題下的高票答案
關於add_cookie時,expiry參數報錯的問題
step3:放飛自我
這兩個問題解決了以後,基本上剩下的都不是什麼大問題了. 這裏說一個以前不知道的小技巧,chrome瀏覽器在源碼審查的時候,能夠選中頁面元素,直接右鍵複製CSS選擇器
這個功能還挺好使的. 表示以前並不知道...
Chrome的CSS選擇器
關於phantomJS瀏覽器的問題
在使用selenium的時候,若是不想看到瀏覽器界面,但是使用 phantomJS這個無界面的瀏覽器來代替. 可是看到pycharm報了個warning. 說是phantomJS已經被depressed. 建議使用headless chrome替代.
因而看了一眼headless chrome怎麼用. 很簡單,在調用chrome的時候傳入一個參數便可.
- chrome_options = Options()
- chrome_options.add_argument('--headless')
- browser = webdriver.Chrome(options=chrome_options)
-
源碼
源碼已上傳github,有須要的請直接下載.
- import os
- import pickle
- import re
- import time
-
- from pyquery import PyQuery as pq
- 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.ui import WebDriverWait
- import pymongo
- from config import *
-
-
- client = pymongo.MongoClient(MONGO_URL)
- db = client[MONGO_DB]
-
-
- browser = webdriver.Chrome()
- wait = WebDriverWait(browser, 10)
-
- def get_taobao_cookies():
- url = 'https://www.taobao.com/'
- browser.get('https://login.taobao.com/')
- while True:
- print("please login to Taobao!")
- time.sleep(4)
- while browser.current_url == url:
- tbCookies = browser.get_cookies()
- browser.quit()
- output_path = open('taobaoCookies.pickle', 'wb')
- pickle.dump(tbCookies, output_path)
- output_path.close()
- return tbCookies
-
- def read_taobao_cookies():
- if os.path.exists('taobaoCookies.pickle'):
- read_path = open('taobaoCookies.pickle', 'rb')
- tbCookies = pickle.load(read_path)
- else:
- tbCookies = get_taobao_cookies()
- return tbCookies
-
- def search():
- try:
-
-
- cookies = read_taobao_cookies()
-
- browser.get('https://www.taobao.com')
- for cookie in cookies:
-
- if 'expiry' in cookie:
- del cookie['expiry']
- browser.add_cookie(cookie)
- browser.get('https://www.taobao.com')
- input_text = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#q')))
- submit = wait.until(
- EC.element_to_be_clickable((By.CSS_SELECTOR, '#J_TSearchForm > div.search-button > button')))
- input_text.send_keys(KEYWORD)
- submit.click()
- total = wait.until(
- EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.total')))
- get_products()
- return total.text
- except TimeoutException:
-
- return search()
-
- def next_page(page_number):
- try:
- input_text = wait.until(
- EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.form > input')))
- submit = wait.until(EC.element_to_be_clickable(
- (By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.form > span.btn.J_Submit')))
- input_text.clear()
- input_text.send_keys(page_number)
- submit.click()
- wait.until(EC.text_to_be_present_in_element(
- (By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > ul > li.item.active > span'), str(page_number)))
- get_products()
- except TimeoutException:
- return next_page(page_number)
-
- def get_products():
- wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-itemlist .items .item')))
- 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()[:-3],
- 'title': item.find('.title').text(),
- 'shop': item.find('.shop').text(),
- 'location': item.find('.location').text()
- }
- save_to_mongo(product)
-
- def save_to_mongo(result):
- try:
- if db[MONGO_TABLE].insert(result):
- print('存儲到MONGODB成功:',result)
- except Exception:
- print('存儲到MONGODB失敗',result)
-
- def main():
- try:
- total = search()
- total = int(re.compile('(\d+)').search(total).group(1))
- for i in range(2, total + 1):
- next_page(i)
- except Exception as exp:
- print('出錯啦',exp)
- finally:
- browser.close()
-
- if __name__ == '__main__':
- main()
-
吾碼2016