使用Selenium模拟浏览器抓取淘宝商品美食信息(含模拟登陆)

淘宝页面比较复杂,含有各种请求参数和加密参数,如果直接请求或者分析Ajax将会非常繁琐。
Selenium是一个自动化测试工具,可以驱动浏览器去完成各种工作,比如模拟点击、输入和下拉等多种功能,这样我们只需关心操作,
不需要关心后台发生了怎么样的请求下面对具体操作步骤进行详述。

所用到的

  • selenium
  • pyqurey
  • re
  • pymongo

数据库截图

实现代码

# -*- coding: utf-8 -*-
"""
@Time : 2021/1/25 17:02
@Auth : Ne-21
@File :taobaospider.py
@IDE :PyCharm
@Motto:Another me.
"""
import re
from selenium.common.exceptions import TimeoutException
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 selenium.webdriver import ActionChains
import time
from pyquery import PyQuery as pq
import pymongo

# Mongo数据库
MONGO_URL = 'localhost'
MONGO_DB = 'taobao'
MONGO_TABLE = 'product'
client = pymongo.MongoClient(MONGO_URL)
db = client[MONGO_DB]

options = webdriver.ChromeOptions()
# options.add_argument('--blink-settings=imagesEnabled=false') # 不加载图片, 提升速度
# options.add_argument('--headless') # 浏览器不提供可视化页面
browser = webdriver.Chrome(options=options)
# 防止被监测
browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
    "source": '''
            Object.defineProperty(navigator, 'webdriver', {
              get: () => undefined
            })
          '''
})
wait = WebDriverWait(browser, 5)

def do_slider():
    """
    处理滑动验证码,没有测试
    :return:
    """
    slider_go = wait.until(
        EC.presence_of_element_located((By.CSS_SELECTOR, '#nc_1_n1z'))
    )
    # 实例化一个动作链关联游览器
    action = ActionChains(browser)
    action.reset_actions()
    # 使用鼠标动作链进行点击并悬浮
    action.click_and_hold(slider_go)
    # 滑动验证码
    action.move_by_offset(xoffset=258, yoffset=0).perform()
    time.sleep(5)

def login(username, password):
    print('正在登陆......')
    browser.get('https://login.taobao.com/member/login.jhtml')
    input_username = wait.until(
        EC.presence_of_element_located((By.CSS_SELECTOR, '#fm-login-id'))
    )
    input_password = wait.until(
        EC.presence_of_element_located((By.CSS_SELECTOR, '#fm-login-password'))
    )
    submit = wait.until(
        EC.element_to_be_clickable((By.CSS_SELECTOR, '#login-form > div.fm-btn > button'))
    )
    input_username.send_keys(username)
    time.sleep(2)
    input_password.send_keys(password)
    time.sleep(2)
    submit.click()
    time.sleep(3)  # 等待检验滑块

    # 判断有无滑块验证
    try:
        slider = wait.until(
            EC.presence_of_element_located((By.CSS_SELECTOR, '#nc_1__scale_text > span'))
        )
        if bool(slider):
            print('发现滑块验证码')
            do_slider()
            submit.click()
        else:
            print('未发现滑块')
            pass
    except:
        print('未发现滑块')

    time.sleep(5)  # 等待短信验证
    # 判断有无短信验证
    try:
        # 定位iframe标签,由于iframe没有id,name这种唯一的属性,因此只能通过先定位,在切换实现
        frame = wait.until(
            EC.presence_of_element_located((By.XPATH, '//*[@id="content"]/div/div[1]/iframe'))
        )
        # 由于手机验证页面出现了页面的嵌套,因此需要进行页面跳转到iframe下
        browser.switch_to.frame(frame)
        sms_button = wait.until(
            EC.presence_of_element_located((By.XPATH, '//*[@id="J_GetCode"]'))
        )
        if bool(sms_button):
            print('发现短信验证码')
            time.sleep(1)
            sms_button.click()
            print('验证码已发送,请输入验证码(20s)')
            time.sleep(20)
            sms_submit = wait.until(
                EC.element_to_be_clickable((By.CSS_SELECTOR, '#submitBtn'))
            )
            sms_submit.click()
        else:
            print('无短信验证')
            pass
    except:
        print('无短信验证...')
        pass
    finally:
        print('登陆成功')

def search():
    print('正在搜索.....')
    try:
        browser.get('https://www.taobao.com')
        # 等待目标元素加载完成
        # input = WebDriverWait(browser, 10).until(
        #     EC.presence_of_all_elements_located(By.CSS_SELECTOR, '#q')
        # )
        # submit = WebDriverWait(browser, 10).until(
        #     EC.element_to_be_clickable(By.CSS_SELECTOR, '#J_TSearchForm > div.search-button > button')
        # )
        # 改写WebDriverWait
        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_products()
        return total.text
    except TimeoutException:
        return search()

# 翻页操作
def next_page(page_number):
    print('正在翻页......')
    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_products()
    except TimeoutException:
        return next_page(page_number)

# 解析网页
def get_products():
    # 商品信息是否存在
    wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-itemlist .items .item')))
    # 拿到网页源代码
    html = browser.page_source
    # pyquery解析
    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):
    print('正在加入数据库......')
    try:
        if db[MONGO_TABLE].insert(result):
            print('存储到MONGODB成功', result)
    except Exception:
        print('存储异常', result)

def main():
    print('开始运行.......')
    login('', '')
    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()

补充

chrome_options.add_argument('--user-agent=""')  # 设置请求头的User-Agent
chrome_options.add_argument('--window-size=1280x1024')  # 设置浏览器分辨率(窗口大小)
chrome_options.add_argument('--start-maximized')  # 最大化运行(全屏窗口),不设置,取元素会报错
chrome_options.add_argument('--disable-infobars')  # 禁用浏览器正在被自动化程序控制的提示
chrome_options.add_argument('--incognito')  # 隐身模式(无痕模式)
chrome_options.add_argument('--hide-scrollbars')  # 隐藏滚动条, 应对一些特殊页面
chrome_options.add_argument('--disable-javascript')  # 禁用javascript
chrome_options.add_argument('--blink-settings=imagesEnabled=false')  # 不加载图片, 提升速度
chrome_options.add_argument('--headless')  # 浏览器不提供可视化页面

chrome_options.add_argument('--ignore-certificate-errors')  # 禁用扩展插件并实现窗口最大化
chrome_options.add_argument('--disable-gpu')  # 禁用GPU加速
chrome_options.add_argument('–disable-software-rasterizer')
chrome_options.add_argument('--disable-extensions')
chrome_options.add_argument('--start-maximized')
转载请注明出处,谢谢!
THE END
分享
二维码
打赏
< <上一篇
下一篇>>