【3】爬虫学习-使用Selenium爬取淘宝商品

这篇博客主要是通过Selenium来模拟浏览器操作,抓取淘宝商品的信息,并将结果保存到MongoDB中。

淘宝为什么需要用所谓的Selenium来进行抓取呢,是因为淘宝这种页面,其Ajax接口包含很多加密参数,我们很难从中找出规律。为了解决这个问题,我们引入Selenium

Selenium简介

Selenium是自动化测试工具,利用它可以驱动浏览器执行特定的动作,比如点击、下拉等操作,同时还可以获取浏览器当前呈现的页面源代码,做到可见即可爬,对于一些JavaScript动态渲染的页面来说,这种抓取很有效。除了需要Selenium之外,还需要与之搭配的浏览器,因此需要Chrome浏览器和ChromeDriver驱动的配置

  • Selenium安装
1
2
>pip install selenium
>
  • ChromDriver安装

首先查看Chrome的版本号:通过点击Chrome的菜单帮助->关于Google Chrome里面就有其版本号

然后根据Chrome的版本号,下载ChromeDriver的型号。

然后配置环境变量,具体看《python3 网络爬虫开发实战》的介绍。

  • Selenium的使用
  • 申明浏览器对象并访问页面
1
2
3
4
5
6
7
>>from selenium import webdriver
>>
>>browser = webdriver.Chrome()
>>browser.get('http://www.taobao.com')
>>print(browser.page_source)
>>browser.close()
>>
  • 查找节点

    1. 单个节点

      查找单个节点比如搜索框,首先要看源码,通过选定页面元素,可以在网页源码中查看到,可以通过find_element_by_name()以及find_element_by_id()或者find_element(BY,ID,id)来获取相关的属性。

    2. 多个节点

      获取多个节点可以通过find_elements()来得到。

    3. 节点交互

      节点交互就是模拟我们平常在网页上的操作。比如下面这个

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    >  >from selenium import webdriver
    > >import time
    > >
    > >browser = webdriver.Chrome()
    > >browser.get('http://www.taobao.com')
    > >input=browser.find_element_by_id('q')
    > >input.send_keys('iphone')
    > >time.sleep(1)
    > >input.clear()
    > >input.send_keys('ipad')
    > >button=browser.find_element_by_class_name('btn-search')
    > >button.click()
    > >

更多的常见节点动作操作,可以查看官方文档

  1. 动作链

    比如执行鼠标拖动、键盘按键灯没有特定执行对象的操作,就需要使用动作链来执行。比如下面这段代码实现将一个节点拖曳至另一个节点处。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    >  >from selenium import webdriver
    > >from selenium.webdriver import ActionChains
    > >
    > >browser = webdriver.Chrome()
    > >url = 'http://www.runoob.com/'
    > >browser.get(url)
    > >browser.switch_to_frame('iframeResult')
    > >source =browser.find_element_by_css_selector('#draggable')
    > >target =browser.find_element_by_css_selector('#droppable')
    > >actions=ActionChains(browser)
    > >actios.drag_and_drop(source,target)
    > >action.perform()
    > >
  1. 执行JavaScript以及获取节点信息

    selenium还可以执行API没有的功能可以用执行JavaScript,通过page_source属性获取网页源代码,接着使用解析库(正则表达式,BeautifulSoup,pyquery)来提取信息。

  2. 切换Frame以及延时等待

    我们网页有一种节点叫iframe,也就是子Frame,相当于页面的子页面,他的结构和外部网页结构完全一致。

  • Splash的使用

Splash是一个JavaScript渲染服务,是一个带有HTTP API的轻量级浏览器,同时他对python中的Twisted和QT库

使用Selenium爬取淘宝商品

爬取思路

爬取淘宝上的商品的爬虫程序主要分为四个大的部分:

  • 获取商品列表

抓取的入口就是淘宝的搜索页面,这个连接可以通过直接构造函数来进行访问,搜索iPad就可以直接通过网址http://s.taobao.com/search?q=ipad将呈现第一页的搜索结果。

  • 解析商品列表

当成功加载了一页商品之后,利用selenium就可以获取页面源代码,然后再用相应的解析库Pyquery库解析就行了。

  • 保存到MongoDB

创建一个MongoDB的连接对象,指定数据库。

  • 遍历每页

商品的搜索结果一般最大都是100页,要获取每页的内容就需要有翻页操作,可以通过在文本框中输入页码,点击确定进行翻页,不推荐使用下一页,因为直接点击下一页容易出现加载失败的情况。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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.wait import WebDriverWait
from util import *
from urllib.parse import quote
from pyquery import PyQuery as pq
import pymongo


browser = webdriver.Chrome()
wait = WebDriverWait(browser,10)

def index_page(page):
"""
抓取索引页
:param page: 页码
"""
try:
url = 'http://s.taobao.com/search?q=' + quote(KEYWORD) # quote对字符串进行URL编码
browser.get(url)
if page>1:
input = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR , '#mainsrp-pager div.form>input')))
submit =wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR,'#mainsrp-pager div.form>span.btn.J_Submit')))
input.clear()
input.send_keys(page)
submit.click()
wait.until(
EC.text_to_be_present_in_element((By.CSS_SELECTOR,'#mainsrp-pager li,item.active > span'),str(page)))
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'.m-itemlist .item .item')))
get_products()
except TimeoutException:
index_page(page)


def get_products():
"""
提取商品数据
"""
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'), # 获取data-src的属性作为商品图片
'price': item.find('.price').text(),
'deal': item.find('.deal-cnt').text(),
'title': item.find('.title').text(),
'shop': item.find('.shop').text(),
'location': item.find('.location').text()
}
print(product)
save_to_mongo(product)


Client = pymongo.MongoClient(MONGO_URL)
db =Client[MONGO_DB]
def save_to_mongo(result):
"""
保存到MongoDB
:param result:结果
:return:
"""
try:
if db[MONGO_COLLECTION].insert(result):
print('存储到MongoDB成功')
except Exception:
print('存储到MongoDB失败')

def main():
"""
遍历每一页
:return:
"""
for i in range(1,MAX_PAGE+1):
index_page(i)

if __name__ == '__main__':
main()