您的位置:首页 > 编程语言 > Python开发

Python爬虫实战03:用Selenium模拟浏览器爬取淘宝美食

2018-03-30 20:31 821 查看

1 目标站点分析

淘宝页面信息很复杂的,含有各种请求参数和加密参数,如果直接请求或者分析Ajax请求的话会很繁琐。所以我们可以用Selenium来驱动浏览器模拟点击来爬取淘宝的信息。这样我们只要关系操作,不用关心后台发生了怎样的请求。

这样有个好处是:可以直接获取网页渲染后的源代码。输出 page_source 属性即可。

这样,我们就可以做到网页的动态爬取了。缺点是速度相比之下比较慢。

2 流程框架

搜索关键词

利用Selenium驱动浏览器搜索关键字,得到查询结果后的商品列表。

分析页码并翻页

得到商品页码数,模拟翻页,得到后续页面的商品列表。

分析提取商品内容

利用PyQuery分析源码,解析得到商品列表。

存储至MongoDB

将商品列表信息存储到数据库MongoDB。

3 爬虫实战

3.1 搜索商品信息
search()

首先声明一个浏览器对象
browser
,有头或者无头。有头的是带界面的,每步操作你都可以看到。无头则是不带界面,在后台运行,速度较快,这里选择无头chrome,配置参数如下。

可能会出错的地方用
try...except
包含起来,保证程序的正常运行。如果发生错误,再次搜索。

然后进入淘宝首页,检查源代码,找到输入框的元素和搜索按钮的元素,可右键复制为css选择器。这里就可以输入文字,以及点击按钮。

selenium之等待。防止元素还没加载完成就运行下一步而报错。 调用
WebDriverWait(browser, 10)
,后面会频繁调用,所以这里改写为
wait
。关于selenium等待的 更多用法,点击文档

# browser = webdriver.Chrome()  # 有头chrome
# 无头chrome 设置参数
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
browser = webdriver.Chrome(chrome_options=chrome_options)

wait = WebDriverWait(browser, 10)  # 改写一下,后面会频繁应用


def search():
"""搜索商品信息"""
print('正在保存第{}页'.format(1))
try:
browser.get('https://www.taobao.com')
# 声明搜索框元素,并且设置等待,presence_of_element_located条件是判断已经加载出来
input = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, "#q"))  # 这里的css选择器,右键网页源代码复制可得
)
# 声明搜索按钮,等待,element_to_be_clickable判断按钮是可以点击的
submit = wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR, '#J_TSearchForm > div.search-button > button'))
)
input.send_keys('美食')  # 输入文字
submit.click()  # 点击按钮
# total 为总页数 presence_of_element_located判断total元素已经加载完成
total = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > div.total'))
)
get_products()
return total.text  # 返回总页数
except TimeoutException:
return search()  # 如果发生错误,再次搜索。


3.2 翻页
next_page(page_number)

在页码框中输入页码,点击按钮实现翻页。检查高亮元素是否在当前代码判断是否翻页成功,这里用到等待条件
text_to_be_present_in_element


def next_page(page_number):
"""下一页 """
print('正在保存第{}页'.format(page_number))
try:
input = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.form > input"))
# 这里的css选择器,右键网页源代码复制可得
)
# 等待,判断按钮是可以点击的
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_products()
except TimeoutException:
next_page(page_number)  # 若失败,在试一次


3.3 获取商品信息
get_products()

这里用chrome的工具分析出来的代码,右键复制的css选择器不知道为什么不行。所以用的是css选择器的另外一种写法。

def get_products():
"""获取商品信息"""
# 判断items元素加载成功
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()  # items()返回一个生成器,生成每个item
for item in items:
product = {
'image': item.find('.pic .img').attr('src'),
'price': item.find('.price').text().replace('\n', ''),
'deal': item.find('.deal-cnt').text()[:-3],
'title': item.find('.title').text(),
'shop': item.find('.shop').text(),
'location': item.find('.location').text()
}  # 构造字典,存储商品信息,准备存入数据库
save_to_mongo(product)


3.4 保存到数据库
save_to_mongo(result)

新建一个配置文件 config.py,保存了连接mongodb所需的参数。

"""config.py"""
MONGO_URL = 'localhost'
MONGO_DB = 'toabao'
MONGO_TABLE = 'meishi'


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


def save_to_mongo(result):
"""保存到数据库"""
try:
if db[MONGO_TABLE].insert(result):
print('存储到数据库成功', result)
except Exception:
print("存储失败")


3.5 主函数
main()

def main():
try:
total = search()
total = int(re.compile('(\d+)').search(total).group(1))  # 强制转换为int类型
for i in range(2, total + 1):
next_page(i)
except Exception:
print('something wrong~!')
finally:  # 保证浏览器关闭
browser.close()


3.6 头文件

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 selenium.webdriver.chrome.options import Options
import pymongo

from config import *


3.7 运行

if __name__ == '__main__':
main()


3.8 结果



3.9 注意

多用try…except…finally保证程序的正常运行。

使用Selenium中,记得在关键操作前加入等待判定,确保所需元素加载完成或者达到我们想要的状态。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: