(九)使用Selenium+Chrome/PhantomJS(模拟浏览器)抓取淘宝商品美食信息|Python3网络爬虫开发实战

96
durian221783310
2018.02.11 14:02* 字数 3660

最近更新:2018-02-11

1.相关工具介绍
2.目标站点分析
3.流程框架及准备工作
4.爬虫步骤
学习参考链接:
Python3网络爬虫开发实战 7.1-Selenium的使用
Python3网络爬虫开发实战 7.4-使用Selenium爬取淘宝商品

1.相关工具介绍

  • Selenium是一个自动化测试工具,利用它可以驱动浏览器执行特定的动作,如点击、下拉等操作,同时还可以获取浏览器当前呈现的页面的源代码,做到可见即可爬。对于一些JavaScript动态渲染的页面来说,此种抓取方式非常有效。
  • PhanttomJS是无界面浏览器,因为老是开着浏览器,不方便.
  • Chrome是个浏览器

2.目标站点分析

本节中,我们要利用Selenium抓取淘宝商品并用pyquery解析得到商品的图片、名称、价格、购买人数、店铺名称和店铺所在地信息,并将其保存到MongoDB。

  • 打开淘宝网:https://www.taobao.com/
  • 搜索一个关键词:美食,看到非常好多吃的,我们现在就是要爬取这些内容.
  • 打开淘宝页面,搜索商品,比如美食,此时打开开发者工具,截获Ajax请求,我们可以发现获取商品列表的接口,如图7-19所示。但是这个Ajax接口包含几个参数,参数不能直接发现其规律,如果要去探寻它的生成规律,也不是做不到,但这样相对会比较烦琐,所以如果直接用Selenium来模拟浏览器的话,就不需要再关注这些接口参数了,只要在浏览器里面可以看到的,都可以爬取。这也是我们选用Selenium爬取淘宝的原因


  • 爬取的顺序是:需要模拟在输入框输入关键词,点击搜索按钮,获取首页的内容,模拟点击翻页,获得每页源代码,并分析商品信息,存储到MongoDB数据库.

3.流程框架及准备工作

3.1流程框架

3.2准备工作

本节中,我们首先以Chrome为例来讲解Selenium的用法。在开始之前,请确保已经正确安装好Chrome浏览器并配置好了ChromeDriver;另外,还需要正确安装Python的Selenium库;最后,还对接了PhantomJS和Firefox,请确保安装好PhantomJS和Firefox并配置好了GeckoDriver。如果环境没有配置好,可参考如下崔庆才的博客链接。
Python3网络爬虫开发实战4.3-使用pyquery
Python3网络爬虫开发实战1.5.2-PyMongo的安装
Python3网络爬虫开发实战1.4.2-MongoDB安装
Python3网络爬虫开发实战1.3.3-pyquery的安装
Python3网络爬虫开发实战1.2.5-PhantomJS的安装
Python3网络爬虫开发实战1.2.3-ChromeDriver的安装
Python3网络爬虫开发实战 1.2.2-Selenium的安装

4.爬虫步骤

4.1声明浏览器对象

4.1.1本次案例声明浏览器方法
from selenium import webdriver
browser = webdriver.Chrome()

Chrome浏览器会自动打开,如下截图,则说明驱动Chrome浏览器成功:


4.1.2声明浏览器拓展学习内容

Selenium支持非常多的浏览器,如Chrome、Firefox、Edge等,还有Android、BlackBerry等手机端的浏览器。另外,也支持无界面浏览器PhantomJS。

此外,我们可以用如下方式初始化:


browser = webdriver.Chrome()
browser = webdriver.Firefox()
browser = webdriver.Edge()
browser = webdriver.PhantomJS()
browser = webdriver.Safari()

这样就完成了浏览器对象的初始化并将其赋值为browser对象。接下来,我们要做的就是调用browser对象,让其执行各个动作以模拟浏览器操作。

4.2定义搜索的方法

4.2.1定义搜索的方法-search()
  • 这里首先构造了一个WebDriver对象,使用的浏览器是Chrome,然后指定一个关键词,如美食.
  • 等待加载时,我们使用了WebDriverWait对象,它可以指定等待条件,同时指定一个最长等待时间,这里指定为最长10秒。如果在这个时间内成功匹配了等待条件,也就是说页面元素成功加载出来了,就立即返回相应结果并继续向下执行,否则到了最大等待时间还没有加载出来时,就直接抛出超时异常。
  • 比如,我们最终要等待商品信息加载出来,就指定了presence_of_element_located这个条件,然后传入了#q这个选择器,而这个选择器对应的内容就是搜索商品的输入框.
  • 关于搜索美食操作,这里首先获取商品输入框,赋值为input,然后获取“确定”按钮,赋值为submit.
  • 调用send_keys()方法将美食填充到输入框中,然后点击“确定”按钮(submit.click())即可。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

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

def search():
    browser.get("https://www.taobao.com/")
    #等待浏览器的加载,需要一点时间,判断浏览器是否加载成功的方法,才进行下面的操作
    input = 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.send_keys("美食") #操作动作
    submit.click()
    
def main():
    search()
    
    
if __name__=='__main__':
    main()
4.2.2selenium的拓展学习内容
  • 官方学习资料:Selenium with Python
  • Python3网络爬虫开发实战7.1-Selenium的使用
  • 显式等待
    这里还有一种更合适的显式等待方法,它指定要查找的节点,然后指定一个最长等待时间。如果在规定时间内加载出来了这个节点,就返回查找的节点;如果到了规定时间依然没有加载出该节点,则抛出超时异常。示例如下:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
 
browser = webdriver.Chrome()
browser.get('https://www.taobao.com/')
wait = WebDriverWait(browser, 10)
input = wait.until(EC.presence_of_element_located((By.ID, 'q')))
button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '.btn-search')))
print(input, button)

这里首先引入WebDriverWait这个对象,指定最长等待时间,然后调用它的until()方法,传入要等待条件expected_conditions。比如,这里传入了presence_of_element_located这个条件,代表节点出现的意思,其参数是节点的定位元组,也就是ID为q的节点搜索框。

这样可以做到的效果就是,在10秒内如果ID为q的节点(即搜索框)成功加载出来,就返回该节点;如果超过10秒还没有加载出来,就抛出异常。

对于按钮,可以更改一下等待条件,比如改为element_to_be_clickable,也就是可点击,所以查找按钮时查找CSS选择器为.btn-search的按钮,如果10秒内它是可点击的,也就是成功加载出来了,就返回这个按钮节点;如果超过10秒还不可点击,也就是没有加载出来,就抛出异常。

运行代码,在网速较佳的情况下是可以成功加载出来的。

4.3获取总页面的页数内容-research()

4.3.1本次案例模拟翻页的方法
  • 首先获取页数有多少页,点击美食搜索之后,下一步肯定是要等待页数加载出来,需要再加一个等待的判断,即
  • 那么,怎样知道有没有跳转到对应的页码呢?我们可以注意到,成功跳转某一页后,页码都会高亮显示,如图7-25所示。total=wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,"#mainsrp-pager > div > div > div > div.total")))



    这里商品的搜索结果一般最大都为100页,要获取每一页的内容,只需要将页码从1到100顺序遍历即可,页码数是确定的。所以,直接在页面跳转文本框中输入要跳转的页码,然后点击“确定”按钮即可跳转到页码对应的页面。

  • 使用wait时间过久会出现异常.因此增加try and except:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC



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

def search():
    try:
        browser.get("https://www.taobao.com/")
        #等待浏览器的加载,需要一点时间,判断浏览器是否加载成功的方法,才进行下面的操作
        input = 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.send_keys("美食") #操作动作
        submit.click()
        total = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,"#mainsrp-pager > div > div > div > div.total")))
        return total.text#返回内容
    except TimeoutException:
        return search()                                         
                                               
def main():
    total=search()
    print(total)
    
if __name__=='__main__':
    main()

最终显示的结果:


  • 需要用正则表达式提取100
    total=search()
    total=int(re.compile('(\d+)').search(total).group(1))#打印出来可能是个字符串,所以要转义为整数
import re
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC



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

def search():
    try:
        browser.get("https://www.taobao.com/")
        #等待浏览器的加载,需要一点时间,判断浏览器是否加载成功的方法,才进行下面的操作
        input = 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.send_keys("美食") #操作动作
        submit.click()
        total = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,"#mainsrp-pager > div > div > div > div.total")))
        return total.text#返回内容
    except TimeoutException:
        return search()                                         
                                               
def main():
    total=search()
    total=int(re.compile('(\d+)').search(total).group(1))
    print(total)
    
if __name__=='__main__':
    main()

最终显示的结果:


4.3.2获得总页面页数的学习内容
  • 获取SELECTOR的目标值方法


4.4循环-遍历每页-next_page(page_number)

-刚才我们所定义的next_page(page_number)方法需要接收参数page,page代表页码。这里我们实现页码遍历即可.

  • 其实现非常简单,只需要调用一个for循环即可。这里定义最大的页码数为100,range()方法的返回结果就是1到100的列表,顺序遍历,调用next_page(page_number)方法即可。
  • 这样我们的淘宝商品爬虫就完成了,最后调用main()方法即可运行。
4.4.1本次循环的方法

1)首先查看淘宝页面,使用页面跳转的方法有两种,一是使用高亮的第1页,第2页,....下一页,而是直接输入第几页
-方法一 ,不推荐使用,具体原因如下:
这里不直接点击“下一页”的原因是:一旦爬取过程中出现异常退出,比如到50页退出了,此时点击“下一页”时,就无法快速切换到对应的后续页面了。此外,在爬取过程中,也需要记录当前的页码数,而且一旦点击“下一页”之后页面加载失败,还需要做异常检测,检测当前页面是加载到了第几页。整个流程相对比较复杂,所以这里我们直接用跳转的方式来爬取页面。

  • 方法二,使用的方式是,直接在页面上写第几页.


2)页面输入框

input = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.form > input")))

3)页面确定按钮

    submit = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,"#mainsrp-pager > div > div > div > div.form > span.btn.J_Submit")))

4)首先清除页面输入框的内容:
input.clear()#清除页码输入框的内容

完整的代码:

def next_page(page_number):
    print("正在翻页",page_number)
    try:
        input = 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.clear()#清除页码输入框的内容
        input.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_product()
    except TimeoutException:
        next_page(page_number)

4.5解析网页-商品列表-get_products()

  • 接下来,我们就可以实现get_products()方法来解析商品列表了。这里我们直接获取页面源代码,然后用pyquery进行解析
  • 首先,调用page_source属性获取页码的源代码,然后构造了PyQuery解析对象,接着提取了商品列表,此时使用的CSS选择器是#mainsrp-itemlist .items .item,它会匹配整个页面的每个商品。它的匹配结果是多个,所以这里我们又对它进行了一次遍历,用for循环将每个结果分别进行解析,每次循环把它赋值为item变量,每个item变量都是一个PyQuery对象,然后再调用它的find()方法,传入CSS选择器,就可以获取单个商品的特定内容了。
  • 可以发现,它是一个img节点,包含id、class、data-src、alt和src等属性。这里之所以可以看到这张图片,是因为它的src属性被赋值为图片的URL。把它的src属性提取出来,就可以获取商品的图片了。不过我们还注意data-src属性,它的内容也是图片的URL,观察后发现此URL是图片的完整大图,而src是压缩后的小图,所以这里抓取data-src属性来作为商品的图片。
  • 因此,我们需要先利用find()方法找到图片的这个节点,然后再调用attr()方法获取商品的data-src属性,这样就成功提取了商品图片链接。然后用同样的方法提取商品的价格、成交量、名称、店铺和店铺所在地等信息,接着将所有提取结果赋值为一个字典product,随后调用save_to_mongo()将其保存到MongoDB即可。
  1. 保存到MongoDB
4.5.1本次解析的方法
  • 商品的代码结构,如下:


  • 判断页面商品信息是否加载成功
    wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,"#mainsrp-itemlist .items .item ")))

  • 获得页面所有选择的内容:
    items=doc('#mainsrp-itemlist .items .item').items()

  • 分析商品图片:
    "image" :item.find(".pic .img").attr("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()



    -完整的代码:

# -*- coding: utf-8 -*-
"""
Created on Sat Feb 10 18:33:26 2018

@author: Administrator
"""
import re
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from pyquery import PyQuery as pq


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

def search():
    try:
        browser.get("https://www.taobao.com/")
        #等待浏览器的加载,需要一点时间,判断浏览器是否加载成功的方法,才进行下面的操作
        input = 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.send_keys("美食") #操作动作
        submit.click()
        total = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,"#mainsrp-pager > div > div > div > div.total")))
        get_product()
        return total.text#返回内容
    except TimeoutException:
        return search()          


def next_page(page_number):
    try:
        input = 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.clear()#清除页码输入框的内容
        input.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_product()
    except TimeoutException:
        next_page(page_number)

def get_product():
    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("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(),
                 }                    
         print(product)
                                               
def main():
    total=search()
    total=int(re.compile('(\d+)').search(total).group(1))
    for i in range(2,total+1):
        next_page(i)
    
if __name__=='__main__':
    main()

-最后显示的结果


4.5.2解析的学习内容

4.6保存在MongoDB

这里首先创建了一个MongoDB的连接对象,然后指定了数据库,随后指定了Collection的名称,接着直接调用insert()方法将数据插入到MongoDB。此处的result变量就是在get_products()方法里传来的product,包含单个商品的信息。

4.6.1本次保存在MongoDB的方法
  • 新建一个配置文件叫untitled2.py,并输入以下代码
MONGO_URL ="localhost"#本地数据库
MONGO_DB="taobao"#数据库的名称
MONGO_TABLE="product"#数据库表的名称
  • 在之前的文件引入mongodb相关数据
import re
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from pyquery import PyQuery as pq
from untitled2 import *#引入mongodb的配置文件
import pymongo#引入mongodb所有的变量
  • 在之前的文件声明mongodb相关信息
client=pymongo.MongoClient(MONGO_URL)
db=client[MONGO_DB]
  • 在之前的文件定义mongodb方法:
def save_to_mongo(result):
    try:
        if db[MONGO_TABLE].insert(result):
            print("存储到MONGODB成功",result)
    except Exception:
        print("存储到MONGODB失败",result)
  • 完整的代码为:
import re
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from pyquery import PyQuery as pq
from untitled2 import *#引入mongodb的配置文件
import pymongo

client=pymongo.MongoClient(MONGO_URL)
db=client[MONGO_DB]


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

def search():
    try:
        browser.get("https://www.taobao.com/")
        #等待浏览器的加载,需要一点时间,判断浏览器是否加载成功的方法,才进行下面的操作
        input = 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.send_keys("美食") #操作动作
        submit.click()
        total = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,"#mainsrp-pager > div > div > div > div.total")))
        get_product()
        return total.text#返回内容
    except TimeoutException:
        return search()          


def next_page(page_number):
    try:
        input = 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.clear()#清除页码输入框的内容
        input.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_product()
    except TimeoutException:
        next_page(page_number)

def get_product():
    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("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(),
                 }                    
         print(product)
         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():
    total=search()
    total=int(re.compile('(\d+)').search(total).group(1))
    for i in range(2,total+1):
        next_page(i)
    browser.close()#把浏览器关掉
    
if __name__=='__main__':
    main()

配置文件

MONGO_URL ="localhost"
MONGO_DB="taobao"
MONGO_TABLE="product"

运行的时候,同时要将配置文件打开,才可以运行.运行的结果如下:



4.6.2MongoDB的学习内容

4.7使用PhantomJS

4.7.1本次使用PhantomJS的方法
  • 因用模拟浏览器打开,有点麻烦,所以改为用PhanttomJS,,是无界面浏览器.
    将browser = webdriver.Chrome()改为browser = webdriver.PhantomJS()
  • 在untitled2.py配置文件增加:
    SERVICE_ARGS=["--load-images=false","--disk-cache=true"]#是数组形式,不加载浏览器图片,开启缓存
  • 在之前文件,增加配置文的变量引入:
    browser = webdriver.PhantomJS(service_args=SERVICE_ARGS)
  • 分别在search()/next_page(page_number)分别增加print("正在搜索")/print("正在翻页",page_number)
  • 完整的代码为:
# -*- coding: utf-8 -*-
"""
Created on Sat Feb 10 18:33:26 2018

@author: Administrator
"""
import re
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from pyquery import PyQuery as pq
from untitled2 import *#引入mongodb的配置文件
import pymongo

client=pymongo.MongoClient(MONGO_URL)
db=client[MONGO_DB]


browser = webdriver.PhantomJS(service_args=SERVICE_ARGS)
wait = WebDriverWait(browser, 10)

browser.set_window_size(1400,900)#设置窗口大小

def search():
    print("正在搜索")
    try:
        browser.get("https://www.taobao.com/")
        #等待浏览器的加载,需要一点时间,判断浏览器是否加载成功的方法,才进行下面的操作
        input = 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.send_keys("美食") #操作动作
        submit.click()
        total = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,"#mainsrp-pager > div > div > div > div.total")))
        get_product()
        return total.text#返回内容
    except TimeoutException:
        return search()          


def next_page(page_number):
    print("正在翻页",page_number)
    try:
        input = 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.clear()#清除页码输入框的内容
        input.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_product()
    except TimeoutException:
        next_page(page_number)

def get_product():
    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("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(),
                 }                    
         print(product)
         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():
    total=search()
    total=int(re.compile('(\d+)').search(total).group(1))
    for i in range(2,total+1):
        next_page(i)
    browser.close()#把浏览器关掉
    
if __name__=='__main__':
    main()

配置文件代码为:

MONGO_URL ="localhost"
MONGO_DB="taobao"
MONGO_TABLE="product"


SERVICE_ARGS=["--load-images=false","--disk-cache=true"]#是数组形式,不加载浏览器图片,开启缓存

运行的时候,同时要将配置文件打开,才可以运行.运行的结果如下:


4.7.2使用PhantomJS的方法

官方网站:PhantomJS

4.8整体代码的完善

4.7.1本次完善代码的方法
  • 在untitled2.py配置文件增加:KEYWORD = "美食"
    然后将search()中的input.send_keys("美食")改为input.send_keys("KEYWORD")
  • 将main(),增加try 和findally
def main():
    try:
        total=search()
        total=int(re.compile('(\d+)').search(total).group(1))
        for i in range(2,total+1):
            next_page(i)
    finally:
        browser.close()#把浏览器关掉

完整的代码

@author: Administrator
"""
import re
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from pyquery import PyQuery as pq
from untitled2 import *#引入mongodb的配置文件
import pymongo

client=pymongo.MongoClient(MONGO_URL)
db=client[MONGO_DB]


browser = webdriver.PhantomJS(service_args=SERVICE_ARGS)
wait = WebDriverWait(browser, 10)

browser.set_window_size(1400,900)#设置窗口大小

def search():
    print("正在搜索")
    try:
        browser.get("https://www.taobao.com/")
        #等待浏览器的加载,需要一点时间,判断浏览器是否加载成功的方法,才进行下面的操作
        input = 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.send_keys("KEYWORD") #操作动作
        submit.click()
        total = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,"#mainsrp-pager > div > div > div > div.total")))
        get_product()
        return total.text#返回内容
    except TimeoutException:
        return search()          


def next_page(page_number):
    print("正在翻页",page_number)
    try:
        input = 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.clear()#清除页码输入框的内容
        input.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_product()
    except TimeoutException:
        next_page(page_number)

def get_product():
    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("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(),
                 }                    
         print(product)
         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)
    finally:
        browser.close()#把浏览器关掉
    
if __name__=='__main__':
    main()

配置文件:

MONGO_URL ="localhost"
MONGO_DB="taobao"
MONGO_TABLE="product"


SERVICE_ARGS=["--load-images=false","--disk-cache=true"]#是数组形式,不加载浏览器图片,开启缓存
KEYWORD = "美食"

Python爬虫
Web note ad 1