Python3网络爬虫开发实战我爱编程

(九)使用Selenium+Chrome/PhantomJS(模

2018-02-11  本文已影响108人  努力奋斗的durian

最近更新:2018-02-11

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

1.相关工具介绍

2.目标站点分析

本节中,我们要利用Selenium抓取淘宝商品并用pyquery解析得到商品的图片、名称、价格、购买人数、店铺名称和店铺所在地信息,并将其保存到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()
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的拓展学习内容
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本次案例模拟翻页的方法
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()

最终显示的结果:


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获得总页面页数的学习内容

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

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

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()

  1. 保存到MongoDB
4.5.1本次解析的方法
# -*- 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的方法
MONGO_URL ="localhost"#本地数据库
MONGO_DB="taobao"#数据库的名称
MONGO_TABLE="product"#数据库表的名称
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所有的变量
client=pymongo.MongoClient(MONGO_URL)
db=client[MONGO_DB]
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的方法
# -*- 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本次完善代码的方法
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 = "美食"

上一篇 下一篇

猜你喜欢

热点阅读