站点分析
- 看了交互,好复杂
- 看了下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