站点分析

  • 看了交互,好复杂
  • 看了下Ajax,好复杂
  • 看了下其他内容,看不懂...

所以,没啥好分析的,直接上selenium吧

源码及遇到的问题

在搜索时,会跳转到登录界面

这个没有办法,是淘宝的反爬虫机制. 因为通过selenium webdriver调用的浏览器会有很多异于正常浏览器的参数,具体生成了啥参数,咱也没看懂.

具体的可以参考下面这个大姐的文章

分析淘宝登陆对selenium爬虫的封杀方案,反爬虫机制的升级

而且阿里不愧是阿里,哪怕webdriver调用的chrome中输入用户名和密码依旧不可以.

网上查了一下,基本是selenium是被封的死死的,基本上比较靠谱的方法就是使用pyppeteer库.

那么问题来了...

  1. 我这次就是玩selenium的,临阵换库,不好.

好了,总结了这么多,最终,发现了淘宝的一个bug. 虽然用户名密码登录的方式会由于ua值校验等问题被拒绝. 但是扫码登录不会...

所以我的解决思路很土,先扫码登录,拿到cookie,然后调用chrome之前,先把cookie写进去. (注意!这里有个坑,很大的坑) 如果不出意外的话,应该是可以的.

step1:干起来! 先取cookie

  1. def get_taobao_cookies(): 


  2. url = 'https://www.taobao.com/' 


  3. browser.get('https://login.taobao.com/') 


  4. while True: 


  5. print("please login to Taobao!") 


  6. # 这里等一下下 


  7. time.sleep(4) 


  8. # 等到界面跳转到首页之后,下手 


  9. while browser.current_url == url: 


  10. tbCookies = browser.get_cookies() 


  11. browser.quit() 


  12. output_path = open('taobaoCookies.pickle', 'wb') 


  13. pickle.dump(tbCookies, output_path) 


  14. output_path.close() 


  15. 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

这个很简单,不做过多描述

  1. def read_taobao_cookies(): 


  2. if os.path.exists('taobaoCookies.pickle'): 


  3. read_path = open('taobaoCookies.pickle', 'rb') 


  4. tbCookies = pickle.load(read_path) 


  5. else: 


  6. tbCookies = get_taobao_cookies() 


  7. return tbCookies 



第二部分:讲cookie载入chrome

这个可把我坑惨了.

先看代码,在search()方法中定义了如何载入cookie

  1. cookies = read_taobao_cookies() 


  2. # add_cookie之前要先打开一下网页,不然他妈的会报invalid domain错误. 日了狗了 


  3. browser.get('https://www.taobao.com') 


  4. for cookie in cookies: 


  5. # stackoverflow查到的,不知道为啥,要把expiry这个键值对删掉,不然的话,会报invalid argument,MD! 


  6. if 'expiry' in cookie: 


  7. del cookie['expiry'] 


  8. browser.add_cookie(cookie) 



这里需要注意的有两点:

  1. 在调用add_cookie()方法之前,必须先打开一个网页.不然的话就会报InvalidCookieDomainException 的错误.
  2. 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的时候传入一个参数即可.

  1. chrome_options = Options() 


  2. chrome_options.add_argument('--headless') 


  3. browser = webdriver.Chrome(options=chrome_options) 



源码

源码已上传github,有需要的请直接下载.

  1. import os 


  2. import pickle 


  3. import re 


  4. import time 



  5. from pyquery import PyQuery as pq 


  6. from selenium import webdriver 


  7. from selenium.common.exceptions import TimeoutException 


  8. from selenium.webdriver.common.by import By 


  9. from selenium.webdriver.support import expected_conditions as EC 


  10. from selenium.webdriver.support.ui import WebDriverWait 


  11. import pymongo 


  12. from config import * 



  13. #连接数据库 


  14. client = pymongo.MongoClient(MONGO_URL) 


  15. db = client[MONGO_DB] 



  16. # 创建Chrome对象 


  17. browser = webdriver.Chrome() 


  18. wait = WebDriverWait(browser, 10) 



  19. def get_taobao_cookies(): 


  20. url = 'https://www.taobao.com/' 


  21. browser.get('https://login.taobao.com/') 


  22. while True: 


  23. print("please login to Taobao!") 


  24. time.sleep(4) 


  25. while browser.current_url == url: 


  26. tbCookies = browser.get_cookies() 


  27. browser.quit() 


  28. output_path = open('taobaoCookies.pickle', 'wb') 


  29. pickle.dump(tbCookies, output_path) 


  30. output_path.close() 


  31. return tbCookies 



  32. def read_taobao_cookies(): 


  33. if os.path.exists('taobaoCookies.pickle'): 


  34. read_path = open('taobaoCookies.pickle', 'rb') 


  35. tbCookies = pickle.load(read_path) 


  36. else: 


  37. tbCookies = get_taobao_cookies() 


  38. return tbCookies 



  39. def search(): 


  40. try: 


  41. # 直接调用get()方法不行了,淘宝有反爬虫机制,所以要先传一个cookies进去 


  42. # browser.get('https://www.taobao.com') 


  43. cookies = read_taobao_cookies() 


  44. # add_cookie之前要先打开一下网页,不然他妈的会报invalid domain错误. 日了狗了 


  45. browser.get('https://www.taobao.com') 


  46. for cookie in cookies: 


  47. # stackoverflow查到的,不知道为啥,要把expiry这个键值对删掉,不然的话,会报invalid argument,MD! 


  48. if 'expiry' in cookie: 


  49. del cookie['expiry'] 


  50. browser.add_cookie(cookie) 


  51. browser.get('https://www.taobao.com') 


  52. input_text = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#q'))) 


  53. submit = wait.until( 


  54. EC.element_to_be_clickable((By.CSS_SELECTOR, '#J_TSearchForm > div.search-button > button'))) 


  55. input_text.send_keys(KEYWORD) 


  56. submit.click() 


  57. total = wait.until( 


  58. EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.total'))) 


  59. get_products() 


  60. return total.text 


  61. except TimeoutException: 


  62. # 注意这是个递归,如果超时的话,就再请求一次 


  63. return search() 



  64. def next_page(page_number): 


  65. try: 


  66. input_text = wait.until( 


  67. EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.form > input'))) 


  68. submit = wait.until(EC.element_to_be_clickable( 


  69. (By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.form > span.btn.J_Submit'))) 


  70. input_text.clear() 


  71. input_text.send_keys(page_number) 


  72. submit.click() 


  73. wait.until(EC.text_to_be_present_in_element( 


  74. (By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > ul > li.item.active > span'), str(page_number))) 


  75. get_products() 


  76. except TimeoutException: 


  77. return next_page(page_number) 



  78. def get_products(): 


  79. wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-itemlist .items .item'))) 


  80. html = browser.page_source 


  81. doc = pq(html) 


  82. items = doc('#mainsrp-itemlist .items .item').items() 


  83. for item in items: 


  84. product = { 


  85. # 不知道为什么,取src的话,会出现一些s.gif的链接,所以改取原始图片 


  86. 'image': item.find('.pic .img').attr('data-src'), 


  87. 'price': item.find('.price').text(), 


  88. 'deal': item.find('.deal-cnt').text()[:-3], 


  89. 'title': item.find('.title').text(), 


  90. 'shop': item.find('.shop').text(), 


  91. 'location': item.find('.location').text() 





  92. save_to_mongo(product) 



  93. def save_to_mongo(result): 


  94. try: 


  95. if db[MONGO_TABLE].insert(result): 


  96. print('存储到MONGODB成功:',result) 


  97. except Exception: 


  98. print('存储到MONGODB失败',result) 



  99. def main(): 


  100. try: 


  101. total = search() 


  102. total = int(re.compile('(\d+)').search(total).group(1)) 


  103. for i in range(2, total + 1): 


  104. next_page(i) 


  105. except Exception as exp: 


  106. print('出错啦',exp) 


  107. finally: 


  108. browser.close() 



  109. if __name__ == '__main__': 


  110. main() 





吾码2016

selenium+chrome抓取淘宝宝贝-崔庆才思路的更多相关文章

  1. selenium+chrome抓取淘宝搜索抓娃娃关键页面

    最近迷上了抓娃娃,去富国海底世界抓了不少,完全停不下来,还下各种抓娃娃的软件,梦想着有一天买个抓娃娃的机器存家里~.~ 今天顺便抓了下马爸爸家抓娃娃机器的信息,晚辈只是觉得翻得手酸,本来100页的数据 ...

  2. selenium+PhantomJS 抓取淘宝搜索商品

    最近项目有些需求,抓取淘宝的搜索商品,抓取的品类还多.直接用selenium+PhantomJS 抓取淘宝搜索商品,快速完成. #-*- coding:utf-8 -*-__author__ =''i ...

  3. Selenium模拟浏览器抓取淘宝美食信息

    前言: 无意中在网上发现了静觅大神(崔老师),又无意中发现自己硬盘里有静觅大神录制的视频,于是乎看了其中一个,可以说是非常牛逼了,让我这个用urllib,requests用了那么久的小白,体会到sel ...

  4. Python爬虫实战八之利用Selenium抓取淘宝匿名旺旺

    更新 其实本文的初衷是为了获取淘宝的非匿名旺旺,在淘宝详情页的最下方有相关评论,含有非匿名旺旺号,快一年了淘宝都没有修复这个. 可就在今天,淘宝把所有的账号设置成了匿名显示,SO,获取非匿名旺旺号已经 ...

  5. Python爬虫学习==>第十二章:使用 Selenium 模拟浏览器抓取淘宝商品美食信息

    学习目的: selenium目前版本已经到了3代目,你想加薪,就跟面试官扯这个,你赢了,工资就到位了,加上一个脚本的应用,结局你懂的 正式步骤 需求背景:抓取淘宝美食 Step1:流程分析 搜索关键字 ...

  6. 使用selenium模拟浏览器抓取淘宝信息

    通过Selenium模拟浏览器抓取淘宝商品美食信息,并存储到MongoDB数据库中. from selenium import webdriver from selenium.common.excep ...

  7. python(27) 抓取淘宝买家秀

    selenium 是Web应用测试工具,可以利用selenium和python,以及chromedriver等工具实现一些动态加密网站的抓取.本文利用这些工具抓取淘宝内衣评价买家秀图片. 准备工作 下 ...

  8. 一次Python爬虫的修改,抓取淘宝MM照片

    这篇文章是2016-3-2写的,时隔一年了,淘宝的验证机制也有了改变.代码不一定有效,保留着作为一种代码学习. 崔大哥这有篇>>小白爬虫第一弹之抓取妹子图 不失为学python爬虫的绝佳教 ...

  9. scrapy抓取淘宝女郎

    scrapy抓取淘宝女郎 准备工作 首先在淘宝女郎的首页这里查看,当然想要爬取更多的话,当然这里要查看翻页的url,不过这操蛋的地方就是这里的翻页是使用javascript加载的,这个就有点尴尬了,找 ...

随机推荐

  1. redis的使用1

    学Linux已经将近一个月了,Linux中讲到的redis的使用,到现在还不回具体的使用在php中,今天周末,于是想把redis的使用搞懂. 网上的资料不算多,但还需要硬着头皮学.其中找到这样一篇关于 ...

  2. Python:数值类型

    数值类型的组成 数值类型可以直接使用的有:整数.浮点数.复数 Python3的整型,可以自动调整大小,当做long使用 整数 int 整数的进制表示 表示形式: 二进制:0b... 八进制:0o... ...

  3. POJ-3821-Dining (拆点网络流)

    这题为什么不能用 左边放食物,中间放牛,后面放水? 原因很简单,假设一头牛喜欢两个食物AB和两种水AB. 此时可以从一个食物A,走到牛A,再走到水A. 但是还可以有另一条路,从另一个食物B,走到该牛A ...

  4. CSS水平垂直居中常见方法总结

    1.元素水平居中 当然最好使的是: margin: 0 auto; 居中不好使的原因: 1.元素没有设置宽度,没有宽度怎么居中嘛! 2.设置了宽度依然不好使,你设置的是行内元素吧,行内元素和块元素的区 ...

  5. 【转】获取Jenkins构建时Git Change Log

    原文:https://www.jianshu.com/p/513ab6915dbd 在基于Jenkins进行CI持续集成的工作,在构建后上传蒲公英时想将本次版本的git commit信息同步到蒲公英的 ...

  6. Leetcode 12,452,455-贪心算法

    Leetcode第12题,整数转罗马数字,难度中等 整个题目比较好理解,难度也不大,就算不过脑子,用一串if也基本上可以解决问题,比如 /** 执行用时:6ms,在所有 Java 提交中击败了52.6 ...

  7. Mac下MyEclipse安装及破解

    一.安装MyEclipse 去 官网下载MyEclipse ,我这里下载的是最新版MyEclipse 2017 CI 5,安装之后不要立即打开,不然会导致后面破解失败. 二.破解 1.下载破解文件,亲 ...

  8. 一、FreeMarker实现对js和css压缩

    1.代码压缩理解:实际上就是将原有的文本中无用的注释.空行.空格去掉来压缩文件的大小.进行js和css压缩会带来如下好处:1)减小了文件的体积,减少文件占用的内存;2)减小了网络传输量和带宽占用; 3 ...

  9. [运维] 如何在云服务器上安装 MySQL 数据库, 并使用 Navicat 实现远程连接管理

    .•●•✿.。.:*.•●•✿.。.:*.•●•✿.。.:*.•●•✿.。.:*.•●•✿.。.:*.•●•✿.。.:*.•.•●•✿.。.:*.•●•✿.。.:*.•●•✿.。.:*.•●•✿.。. ...

  10. Wcf托管在IIS中,HttpContext.Current为空

    config中需要配置 <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/> 另需要在服务类上加 ...