selenium 实战爬取淘宝信息-excepted_conditions和WebDriverWait

selenium 高级用法--excepted_conditions和WebDriverWait
看了崔静觅大大的博客,这里算是写出自己对内容的一些理解还有一个实操的小项目:
selenium爬取淘宝商品
另外附上另一篇
selenium爬取京东商品

环境: python3, pymongo, selenium, Chromedrive,chrome浏览器, pyquery,mongo数据库
先说一下爬虫的思想:
对于淘宝来说使用了js进行加密数据,我们这里使用可见即可爬的工具selenium进行爬取,过程如下:

分析请求-> 找到目标信息-> 构造请求-> 提取信息-> 自动执行(翻页)

整个小demo有4个函数:

  • save_to_mongo()
    储存数据的接口
  • get_products()
    获取每页商品的信息
  • index_page()
    判断是否加载,执行完成后推送给页面分析
    *main()
    实现翻页功能
    这里会详细介绍每行代码的意义,上代码:
import pymongo
from selenium import webdriver
from selenium.common.exceptions import TimeoutException  # 超时错误
from selenium.webdriver.common.by import By   # 选择方式的模块
from selenium.webdriver.support.wait import WebDriverWait  # 显示等待
from selenium.webdriver.support import expected_conditions as EC # 条件支持
from urllib.parse import quote  # 屏蔽特殊字符
from pyquery import PyQuery as pq  # pyquery 查找分析节点

# 创建一个谷歌浏览器对象
browser = webdriver.Chrome()  
# 设置等待时间最长为3s
wait = WebDriverWait(browser, 3)
# 搜索关键字,可以整合到config文件里
KEYWORDS = 'iphone'
# mongo的地址,这里可以使用远端的地址,实现分布式
MONGO_URL = 'localhost'
# 数据库名字
MONGO_DB = 'taobao'
# 数据库集合
MONGO_COLLECTION = 'products'
# 创建一个数据库对象
client = pymongo.MongoClient(MONGO_URL, 27017)
# 指定数据库名
db = client.taobao
# 指定爬取页码
MAX_PAGE = 100


def save_to_mongo(result):
    '''
    把结果保存起来
    :param result: 解析过后的商品信息
    :return:
    '''
    try:
        if db[MONGO_COLLECTION].insert(result):  # 这里使用了插入操作,更详细的应该是有去重回滚等操作这里不做演示
            print('save result successfully')
    except Exception:
        print('fail to save')


def get_products():
    '''
    提取商品的数据
    :return:
    '''
    html = browser.page_source # 提取渲染过后的源码
    doc = pq(html)  # 创建pyquery对象,用于css选择器来提取信息
    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(),
            'title': item.find('.title').text(),
            'shop': item.find('.shop').text(),
            'location': item.find('.location').text()
        }
        print(product)
        # 传送给储存功能函数 
        save_to_mongo(product)


def index_page(page):
    '''
    抓取索引页
    :param page:页码
    :return:
    '''
    print('正在爬取第{}页...'.format(page))
    url = 'https://s.taobao.com/search?q=' + quote(KEYWORDS)
    browser.get(url)
    print(page)
    if page > 1:
        print(page)
        input = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager div.form > input')))  # 指定商品页面元素加载出来就继续往下执行,如果到时间没有加载会直接报错
        print(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() # 点击操作
        print('done')
    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 .items .item')))
    get_products() # 等待指定的元素加载出来就可以继续往下执行否则报错



def main():
    for i in range(1, MAX_PAGE + 1):
        index_page(i)


if __name__ == '__main__':
main()

感兴趣的可以把这个在电脑上运行一下试试,看看会得到什么.
另外 Chrome从59版本开始,支持无界面模式 Headless 模式,启用方式:

chrome_options = wedriver.ChromeOptions()
chrome_options.add_argument('--headless')
browser = webdriver.Chrome(chrome_options=chrome_options)

感兴趣的同学可以把浏览器换成Firefox和PhantomJs试试,PhantomJs支持禁用图片加载功能,可以进一步提高爬虫效率

SERVICE_ARGS = ['--load-images=false','--disk-cache=true']
browser = webdriver.PhatomJs(service_args= SERVICE_ARGS)

整个例子到这里结束了,我们来看下里面关于selenium等待的和条件判断的两个方法

excepted_conditions
selenium.webdriver.support.expected_conditions(模块)
用于判断用户的传入的模块是否符合我们的需求,比如上面例子里写的,是否加载完成是否可见都可以作为判断标准,用于判断页面加载进度是否达到了我们的爬去需求.更多详细的方法看这里 第7点,关于等待的用法.

WebDriverWait

  • 参数:
    WebDriverWait(driver, timeout, poll_frequency, ignored_exceptions)

driver: 传入WebDriver实例,即我们上例中的driver
timeout: 超时时间,等待的最长时间(同时要考虑隐性等待时间)
poll_frequency: 调用until或until_not中的方法的间隔时间,默认是0.5秒
ignored_exceptions: 忽略的异常,如果在调用until或until_not的过程中抛出这个元组中的异常,
则不中断代码,继续等待,如果抛出的是这个元组外的异常,则中断代码,抛出异常。默认只有NoSuchElementException。

  • 等待方式
    .until(method, message)
    until

method: 在等待期间,每隔一段时间(init中的poll_frequency)调用这个传入的方法,直到返回值不是False
message: 如果超时,抛出TimeoutException,将message传入异常

not_until
与上方信息操作相反
这里注意的一点就是method参数,这个参数一定是可以调用的,一定要有 call() 方法,否则会抛出异常

综上所写,那么完整的方式应该是下面的结构

WebDriverWait(driver, timeout, poll_frequency, ignored_exceptions).until(method, message)

具体的实现方式就像例子里一样, 等待配合判断来进行爬虫的操作可以,缩短爬虫的等待时间实现爬虫的效率的最大化,极大的提高爬虫的效率.

感谢崔静觅大大的教程!

你可能感兴趣的:(selenium 实战爬取淘宝信息-excepted_conditions和WebDriverWait)