python进阶-05-利用Selenium来实现动态爬虫

python进阶-05-利用Selenium来实现动态爬虫

一.说明

这是python进阶部分05,我们上一篇文章学习了Scrapy来爬取网站,但是很多网站需要登录才能爬取有用的信息,或者网站的静态部分是一个空壳,内容是js动态加载的,或者人机验证,请求拦截转发等,那么这种情况Scrapy来爬取就很费劲,有人说我们可以分析登录接口,js加载内容实现爬取我们需要的内容,哼哼你想多了,请求内容经过服务器转发给你加过包的!所以还是不行,那就没有办法来抓取我们想要的数据了么?

有,就是Selenium动态爬取网页信息,Selenium会启动和控制浏览器直接实现自动登录,Selenium直接运行在浏览器中从而可以直接爬取js加载完的信息。

那么Selenium这么强大有没有什么缺陷?也是有的,效率不高!

但省事啊,就跟Python一样!人生苦短,我用Python,好,继续开始我们的日拱一卒,让我们彻底掌握这一技术!。

二.安装

要使用Selenium,就得先安装,但是Selenium安装不仅仅需要安装Selenium python库,还要在python虚拟环境中安装对应的浏览器驱动!所以安装Selenium分别为 安装Selenium Python库 下载和安装浏览器及对应浏览器的驱动

  1. 下载Selenium库

    pip install selenium -i http://pypi.doubanio.com/simple --trusted-host pypi.doubanio.com
    
  2. 下载对应浏览器和驱动

    1. Chrome的驱动chromedriver

      #谷歌浏览器驱动官方
      https://chromedriver.storage.googleapis.com/index.html 
      # 谷歌浏览器官方开发者文档
      # https://developer.chrome.com/docs/chromedriver/downloads?hl=zh-cn
      #谷歌浏览器历史版本下载
      https://downzen.com/en/windows/google-chrome/versions/?page=1
      #禁用谷歌浏览器更新,大家可看下面的文章,在此不进行重复说明
      #chrome://version/ 查看浏览器版本和安装文件夹
      https://blog.csdn.net/weixin_65228312/article/details/141724054
      
      

      在这里插入图片描述

      通过测试发现chromedriver下载的均为支持最新版本的谷歌浏览器,大家安装最新浏览器即可!

      如果驱动不支持 会提示您应该安装的浏览器版本,安装指定浏览器版本,和禁用浏览器更新即可。

    2. Firefox的驱动geckodriver下载地址

      https://github.com/mozilla/geckodriver/releases/
      

      在这里插入图片描述

    3. IE/微软Edge的驱动IEdriver下载地址

      https://www.nuget.org/packages/Selenium.WebDriver.IEDriver/
      
  3. 为了帮助大家快速理解,我已经准备了一套Firefox浏览器和对应驱动geckodriver,一套谷歌131版本的浏览器驱动,在我的资源里面,大家可以直接下,下载地址如下

    #Firefox的驱动geckodriver
    https://download.csdn.net/download/Lookontime/90059540
    #Chrome的驱动chromedriver
    https://download.csdn.net/download/Lookontime/90091812
    
  4. 如何安装,浏览器直接安装,geckodriver.exe 驱动文件放到 我们的虚拟python环境的Scripts中即可

    #直接复制到虚拟环境 Scripts中即可,如果没有装虚拟环境的小伙 直接将驱动放到python跟目录下
    F:\python_demo_07\my_venv\Scripts
    

三.启动selenium驱动浏览器的方法

  1. 启动谷歌浏览器来爬取内容

    from selenium import webdriver
    from selenium.webdriver.common.keys import Keys #提供键盘按键的支持,如回车键 RETURN
    
    browser = webdriver.Chrome(executable_path="F:/python_demo_07/my_venv/Scripts/chromedriver.exe")
    browser.get('http://www.myurlhub.com')
    elem = browser.find_element_by_name("q") #获取节点
    elem.clear()                            #清除搜索框中的默认文本
    elem.send_keys("pycon")                 #输入 "pycon"
    elem.send_keys(Keys.RETURN)             #模拟按下键盘的回车键 RETURN,触发搜索
    assert "No results found." not in driver.page_source #断言页面标题中包含 "Python"。如果不包含,则抛出异常
    browser.close() #关闭浏览器窗口
    
  2. 启动Firefox

    from selenium import webdriver
    browser = webdriver.Firefox(executable_path="F:/python_demo_07/my_venv/Scripts/geckodriver.exe")
    browser.get('http://www.myurlhub.com')
    
  3. 启动IE(不推荐 古老项目可能需要吧)

    from selenium import webdriver
    browser = webdriver.Ie(executable_path="F:/python_demo_07/my_venv/Scripts/IEDriver .exe")
    browser.get('http://www.myurlhub.com')
    

四.selenium的详细用法

4.1 声明浏览器对象

from selenium import webdriver
browser = webdriver.Chrome()
browser = webdriver.Firefox()
browser = webdriver.Safari()
browser = webdriver.Edge()
browser = webdriver.PhantomJS()

4.2 访问页面

from selenium import webdriver
browser = webdriver.Chrome(executable_path="F:/python_demo_07/my_venv/Scripts/chromedriver.exe")
browser.get('http://www.myurlhub.com')
print(browser.page_source) #打印页面源代码
browser.close() #关闭浏览器窗口

4.3 查找单个元素

from selenium import webdriver
from selenium.webdriver.common.by import By #
browser = webdriver.Chrome(executable_path="F:/python_demo_07/my_venv/Scripts/chromedriver.exe")
browser.get('http://www.myurlhub.com')
# 1. 根据 ID 查找元素
element_by_id = browser.find_element(By.ID, "element_id")
element_by_id = browser.find_element_by_id("element_id")

# 2. 根据 name 属性查找元素
element_by_name = browser.find_element(By.NAME, "element_name")

# 3. 根据 class 名称查找元素
element_by_class_name = browser.find_element(By.CLASS_NAME, "class_name")
element_by_class_name = browser.find_element_by_css_selector("#class_name")
# 4. 根据标签名查找元素
element_by_tag_name = browser.find_element(By.TAG_NAME, "tag_name")

# 5. 使用 CSS 选择器查找元素
element_by_css = browser.find_element(By.CSS_SELECTOR, ".class_name #element_id")

# 6. 使用 XPath 查找元素
element_by_xpath = browser.find_element(By.XPATH, "//div[@class='class_name']")
browser.close() #关闭浏览器窗口

4.4 查找多个元素

from selenium import webdriver
from selenium.webdriver.common.by import By

# 启动 Chrome 浏览器
browser = webdriver.Chrome(executable_path="F:/python_demo_07/my_venv/Scripts/chromedriver.exe")

# 打开指定网址
browser.get('http://www.myurlhub.com')

# 1. 根据 class 名查找多个元素
elements_by_class_name = browser.find_elements(By.CLASS_NAME, "class_name")
element_by_class_name = browser.find_element_by_css_selector("#class_name")
# 2. 根据标签名查找多个元素
elements_by_tag_name = browser.find_elements(By.TAG_NAME, "tag_name")

# 3. 使用 CSS 选择器查找多个元素
elements_by_css = browser.find_elements(By.CSS_SELECTOR, ".class_name #element_id")

# 4. 使用 XPath 查找多个元素
elements_by_xpath = browser.find_elements(By.XPATH, "//div[@class='class_name']")

# 输出查找到的元素个数
print(f"找到 {len(elements_by_class_name)} 个元素")

4.5元素的交互操作

from selenium import webdriver
from selenium.webdriver.common.by import By

# 启动 Chrome 浏览器
browser = webdriver.Chrome(executable_path="F:/python_demo_07/my_venv/Scripts/chromedriver.exe")

# 打开指定网址
browser.get('http://www.myurlhub.com')

#点击按钮
button = browser.find_element(By.ID, "submit_button")
button.click()  # 点击按钮

#输入文本
input_box = browser.find_element(By.NAME, "username")
input_box.send_keys("my_username")  # 输入文本

#清除文本框内容
input_box.clear()  # 清空输入框

#获取元素文本
paragraph = browser.find_element(By.TAG_NAME, "p")
print(paragraph.text)  # 输出段落的文本内容

#获取元素属性
link = browser.find_element(By.LINK_TEXT, "Python")
href = link.get_attribute("href")  # 获取链接的 href 属性
print(href)

#提交表单
form = browser.find_element(By.ID, "search_form")
form.submit()  # 提交表单

#悬停操作

from selenium.webdriver.common.action_chains import ActionChains #引入动作链

element = browser.find_element(By.ID, "hover_element")
actions = ActionChains(browser)
actions.move_to_element(element).perform()  # 悬停在元素上

#拖放操作
source = browser.find_element(By.ID, "drag_source")
target = browser.find_element(By.ID, "drop_target")

actions = ActionChains(browser)
actions.drag_and_drop(source, target).perform()  # 拖放操作

#键盘操作
from selenium.webdriver.common.keys import Keys

input_box = browser.find_element(By.NAME, "query")
input_box.send_keys("selenium" + Keys.ENTER)  # 输入文本并回车

#切换到 iframe
iframe = browser.find_element(By.TAG_NAME, "iframe")
browser.switch_to.frame(iframe)  # 切换到 iframe

4.6 执行JavaScript 脚本

#执行简单 JavaScript 脚本
browser.execute_script("alert('Hello from Selenium!');")
#操作 DOM 元素
element = browser.find_element(By.ID, "my_element")
browser.execute_script("arguments[0].style.backgroundColor = 'yellow';", element)
#获取js执行结果
title = browser.execute_script("return document.title;")
print(title)  # 输出页面标题
#滚动页面
# 滚动到页面底部
browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")

# 滚动到特定元素
element = browser.find_element(By.ID, "target_element")
browser.execute_script("arguments[0].scrollIntoView(true);", element)
#添加动态内容
browser.execute_script("document.body.innerHTML += '<p>Added by Selenium</p>';")
#处理窗口大小和位置
# 调整窗口大小
browser.execute_script("window.resizeTo(1024, 768);")

# 获取窗口位置
position = browser.execute_script("return window.screenX, window.screenY;")
print(position)

4.7 获取元素信息

element = browser.find_element(By.ID, "my_element")
print(element.text)  # 输出元素的文本内容


element = browser.find_element(By.NAME, "username")
value = element.get_attribute("value")  # 获取输入框的值
print(value)

href = element.get_attribute("href")  # 获取链接的 href 属性
print(href)

element = browser.find_element(By.CLASS_NAME, "button")
color = element.value_of_css_property("color")  # 获取按钮的文字颜色
print(color)

element = browser.find_element(By.ID, "my_element")
print(element.tag_name)  # 输出标签名,如 'div'、'input'

element = browser.find_element(By.ID, "my_element")
print(element.size)      # 输出元素的宽度和高度 {'width': 100, 'height': 50}
print(element.location)  # 输出元素的位置 {'x': 50, 'y': 100}

element = browser.find_element(By.ID, "my_element")
print(element.is_displayed())  # 检查元素是否可见
print(element.is_enabled())    # 检查元素是否启用
print(element.is_selected())   # 检查复选框或单选按钮是否选中


element = browser.find_element(By.ID, "my_element")
print(element.is_displayed())  # 检查元素是否可见
print(element.is_enabled())    # 检查元素是否启用
print(element.is_selected())   # 检查复选框或单选按钮是否选中


element = browser.find_element(By.ID, "my_element")
print(element.get_attribute("outerHTML"))  # 输出元素的完整 HTML
print(element.get_attribute("innerHTML"))  # 输出元素内部的 HTML

4.8 等待

等待的目的是确保操作的元素已经出现在页面上,避免因加载延迟导致的异常,Selenium 中等待分为隐式等待和显式等待

4.8.1 隐式等待

对整个 WebDriver 会话生效,隐式等待会在查找元素时,等待一定的时间。如果在超时时间内找到了元素,就继续执行;如果超时,抛出 NoSuchElementException

from selenium import webdriver

browser = webdriver.Chrome()
browser.implicitly_wait(10)  # 设置隐式等待时间为10秒

browser.get("http://example.com")
element = browser.find_element(By.ID, "my_element")  # 如果元素在10秒内加载完成,立即返回

4.8.2 显式等待

显式等待会针对特定条件或特定元素等待指定时间。可以结合条件使用,比如等待元素可见、可点击等。

Selenium 提供了一些常见的等待条件,配合显式等待使用:

  • presence_of_element_located: 等待元素出现在 DOM 中,但不一定可见。
  • visibility_of_element_located: 等待元素出现在 DOM 中并可见。
  • element_to_be_clickable: 等待元素可以被点击。
  • text_to_be_present_in_element: 等待某元素的文本出现。
  • alert_is_present: 等待弹窗出现。
#等待元素点击
from selenium.webdriver.common.by import By
from selenium.webdriver.common.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

browser = webdriver.Chrome()

browser.get("http://example.com")

# 等待最多10秒,直到元素可被点击
element = WebDriverWait(browser, 10).until(
    EC.element_to_be_clickable((By.ID, "my_element"))
)
element.click()  # 点击元素



#等待元素可见
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 等待元素可见,最多 10 秒
element = WebDriverWait(browser, 10).until(
    EC.visibility_of_element_located((By.CLASS_NAME, "visible-element"))
)
element2 = WebDriverWait(self.driver, 10).until(
    EC.presence_of_element_located((By.CSS_SELECTOR, 'p img'))
)
print(element.text)  # 输出元素文本






#等待文本出现在元素中,等待元素中出现特定文本 "Success"。
element = WebDriverWait(browser, 10).until(
    EC.text_to_be_present_in_element((By.ID, "status"), "Success")
)
print("Text found!")


#等待多个元素加载完成
elements = WebDriverWait(browser, 10).until(
    EC.presence_of_all_elements_located((By.TAG_NAME, "li"))
)
for element in elements:
    print(element.text)

#等待按钮变为可点击状态
button = WebDriverWait(browser, 10).until(
    EC.element_to_be_clickable((By.CSS_SELECTOR, ".submit-button"))
)
button.click()  # 点击按钮


#等待 iframe 可切换
iframe = WebDriverWait(browser, 10).until(
    EC.frame_to_be_available_and_switch_to_it((By.TAG_NAME, "iframe"))
)
print("Switched to iframe")
iframe = WebDriverWait(browser, 10).until(
    EC.frame_to_be_available_and_switch_to_it((By.TAG_NAME, "iframe"))
)
print("Switched to iframe")


# 等待 alert 弹窗出现
alert = WebDriverWait(browser, 10).until(EC.alert_is_present())
alert.accept()  # 接受 alert 弹窗

#等待元素属性变化 等待元素的 class 属性变为 "completed"。
element = browser.find_element(By.ID, "progress")
WebDriverWait(browser, 10).until(
    lambda driver: element.get_attribute("class") == "completed"
)
print("Progress completed!")


#等待页面标题变更
WebDriverWait(browser, 10).until(EC.title_contains("Dashboard"))
print("Page loaded with expected title!")


#等待特定元素不可见
WebDriverWait(browser, 10).until(
    EC.invisibility_of_element_located((By.ID, "loading-spinner"))
)
print("Spinner disappeared!")


#等待文件下载完成(JavaScript 控制按钮触发下载)点击下载按钮后,通过检查页面的 cookie 确认文件下载完成。
download_button = WebDriverWait(browser, 10).until(
    EC.element_to_be_clickable((By.ID, "download-btn"))
)
download_button.click()

WebDriverWait(browser, 20).until(
    lambda driver: "file_downloaded=true" in driver.execute_script("return document.cookie")
)
print("File download completed!")

4.9 浏览器的前进和后退,刷新等操作

from selenium import webdriver
import time

browser = webdriver.Chrome()

# 打开两个页面
browser.get("https://www.example.com")
time.sleep(2)  # 等待页面加载
browser.get("https://www.google.com")
time.sleep(2)

# 后退到第一个页面
browser.back()
print("后退到:", browser.current_url)

# 前进到第二个页面
browser.forward()
print("前进到:", browser.current_url)

# 刷新页面
browser.refresh()
print("页面已刷新")

4.10 cookies处理(了解即可 selenium 不需要操作cookies)

from selenium import webdriver

browser = webdriver.Chrome()

# 打开网站
browser.get("https://www.example.com")

# 添加 Cookie
browser.add_cookie({"name": "my_cookie", "value": "cookie_value"})

# 获取所有 Cookies
print("所有 Cookies:", browser.get_cookies())

# 获取指定 Cookie
print("单个 Cookie:", browser.get_cookie("my_cookie"))

# 删除指定 Cookie
browser.delete_cookie("my_cookie")

# 删除所有 Cookies
browser.delete_all_cookies()
# 刷新页面以使添加和删除cookie 生效
browser.refresh()

browser.quit()

4.11 JWT令牌处理(了解即可 selenium 不需要操作JWT 和发送请求)

#方式一 

from selenium import webdriver
from selenium.webdriver.common.by import By

# 初始化浏览器
browser = webdriver.Chrome()

# 打开目标页面(需与 JWT 的域匹配)
browser.get("https://www.example.com")

# 添加 JWT 令牌到 Cookie
jwt_token = "your_jwt_token_here"
browser.add_cookie({
    "name": "Authorization",  # 一般服务端会使用这个名称,但请根据具体情况修改
    "value": f"Bearer {jwt_token}",
    "domain": "www.example.com",  # 确保域名与当前页面匹配
    "path": "/"
})

# 刷新页面或访问需要 JWT 身份验证的页面
browser.refresh()

# 验证是否登录成功
print("Current URL:", browser.current_url)

#方式二

browser.execute_script("""
    fetch('https://www.example.com/protected', {
        method: 'GET',
        headers: {
            'Authorization': 'Bearer your_jwt_token_here'
        }
    }).then(response => response.json()).then(data => console.log(data));
""")

4.12 切换页面操作

#页面切换
from selenium import webdriver
import time

browser = webdriver.Chrome()

# 打开第一个页面
browser.get("https://www.example.com")
print("当前窗口句柄:", browser.current_window_handle)

# 打开新标签页
browser.execute_script("window.open('https://www.google.com');")
time.sleep(2)  # 等待页面加载

# 获取所有窗口句柄
handles = browser.window_handles
print("所有窗口句柄:", handles)

# 切换到新标签页(第二个窗口)
browser.switch_to.window(handles[1])
print("当前窗口句柄:", browser.current_window_handle)
print("当前页面 URL:", browser.current_url)

# 切换回第一个窗口
browser.switch_to.window(handles[0])
print("当前窗口句柄:", browser.current_window_handle)
print("当前页面 URL:", browser.current_url)

browser.quit()

#iframe 切换
from selenium import webdriver

browser = webdriver.Chrome()
browser.get("https://www.example.com")

# 切换到 iframe
iframe = browser.find_element_by_tag_name("iframe")
browser.switch_to.frame(iframe)

# 在 iframe 内部执行操作
element = browser.find_element_by_id("inner_element")
element.click()

# 切换回主页面
browser.switch_to.default_content()

# 继续在主页面操作
browser.quit()

五.案例一 爬取翻译内容(技术文章仅用于学习与研究目的,不得用于违法行为,如需要翻译接口请购买正版翻译接口)

别看百度翻译很简单,其实我们直接Requests百度翻译或者Scrapy 会发现当字符超过一定长度,就无法获取结果,因为页面结果是js动态生成的!

针对这种情况,就需要分析页面结构,隐藏接口等情况,才能爬取,且翻译的字符超过一定数量接口就会改变,导致我们在做百度翻译,失败!

但是现在不同的!这时候就适合用selenium技术!不用哪些花里胡哨的的操作!

但是利用selenium技术,爬取页面内容会很慢,如需翻译接口,请购买百度翻译接口,本文主要是用来解释selenium技术。

1.开发环境

python 3.6.8

火狐浏览器:65.0.2 (64 位)

#Firefox的驱动geckodriver
https://download.csdn.net/download/Lookontime/90059540

1.我们新建一个FastAPI接口,创建和启用FastAPI接口,看我的这篇文章:

https://blog.csdn.net/Lookontime/article/details/143696629

2.在项目文件夹中创建main.py 代码如下

#main.py

from fastapi import FastAPI
from api.crawler import fanyi
app = FastAPI()



# 包含用户相关的所有路由
app.include_router(fanyi.router, prefix="/crawler", tags=["CrawlerAPI"])

3.创建api文件夹 用作FastAPI路由

api文件夹下新建:__init__.py 文件 及crawler文件夹,其中__init__.py无任何内容

crawler文件夹下新建:fanyi.pyparams.py 文件

代码如下:

params.py 文件

#params.py
from pydantic import BaseModel
from typing import List, Optional
class FanyiParams(BaseModel):
    query: str
    lang: str = 'en2zh'
    ext_channel: str = 'DuSearch'

fanyi.py文件

#fanyi.py
from fastapi import APIRouter, HTTPException
from selenium import webdriver
from .params import *
#确保页面加载完成,避免异步调用导致异常
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

router = APIRouter()

@router.post("/baidu_fanyi")
def baidu_fanyi(params:FanyiParams):
    try:
        # 设置 Firefox 的无头模式
        options = Options()
        options.headless = True  # 启用无头模式,避免打开实际浏览器
        browser = webdriver.Firefox(executable_path="F:/python_demo_07/my_venv/Scripts/geckodriver.exe", options=options)
        browser.get(f'https://fanyi.baidu.com/mtpe-individual/multimodal?query={params.query}&lang={params.lang}&ext_channel={params.ext_channel}')

        # 等待页面中某个元素加载完成
        WebDriverWait(browser, 10).until(
            EC.presence_of_element_located((By.ID, 'trans-selection'))
        )

        fanyi = browser.find_element(By.ID, "trans-selection")
        fanyi_text = fanyi.text
        print("翻译结果",fanyi_text)
        browser.close() 
        # html = browser.page_source  # 获取完整 HTML 内容  
        return fanyi_text
    except Exception as e:
        print(f"发生错误: {e}")
        return {"error": "无法获取翻译结果"}

4.启动FastAPI

(my_venv) PS F:\python_demo_07> uvicorn main:app  --port 8082

但是很抱歉截止文章发布前,这种原生的selenium应用已经无法爬取翻译内容了

5.升级selenium

开发环境,这次我们用谷歌浏览器

python 3.12.6

谷歌浏览器:131.0.6778.109

#Chrome的驱动chromedriver
https://download.csdn.net/download/Lookontime/90091812

插件:undetected_chromedriver

pip install undetected_chromedriver -i http://pypi.doubanio.com/simple --trusted-host pypi.doubanio.com

因为selenium很容易被检测到是selenium驱动的浏览器,所以我们需要让浏览器检测不到

代码替换如下:

from fastapi import APIRouter, HTTPException

from .params import *
#确保页面加载完成,避免异步调用导致异常
import undetected_chromedriver as uc
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


router = APIRouter()


@router.post("/baidu_fanyi")
def baidu_fanyi(params:FanyiParams):
    try:
        # 设置 无头模式
        options = uc.ChromeOptions()
        
        # 添加无头模式选项
        options.add_argument('--headless')
        # 添加其他必要参数
        options.add_argument('--disable-gpu')  # 禁用 GPU
        options.add_argument('--no-sandbox')  # 避免沙盒模式问题(可选)
        options.add_argument('--disable-dev-shm-usage')  # 防止共享内存问题(可选)
        options.add_argument('--window-size=1920,1080')  # 设置窗口大小
        options.add_argument('--disable-blink-features=AutomationControlled')  # 禁用自动化控制检测
        browser = uc.Chrome(
            executable_path="F:/开发源码/python_demo_07/my_venv_3_12_6/Scripts/chromedriver.exe", 
            options=options
        )
        browser.get(f'https://fanyi.baidu.com/mtpe-individual/multimodal?query={params.query}&lang={params.lang}&ext_channel={params.ext_channel}')

        # 等待页面中某个元素加载完成
        WebDriverWait(browser, 10).until(
            EC.presence_of_element_located((By.ID, 'trans-selection'))
        )

        fanyi = browser.find_element(By.ID, "trans-selection")
        fanyi_text = fanyi.text
        print("翻译结果",fanyi_text)
        browser.close() 
        # html = browser.page_source  # 获取完整 HTML 内容  
        return fanyi_text
    except Exception as e:
        print(f"发生错误: {e}")
        return {"error": "无法获取翻译结果"}

ok这次我们又可以了

六.案例二 利用selenium技术爬取壁纸(技术文章仅用于学习与研究目的,不得用于违法行为,如需要壁纸请购买)

这次我们测试selenium技术的壁纸网站是https://pic.netbian.com/new/ 我看很多大佬已经拿这个网站实验过了,但是现在想爬这个网站是有点难度了,因为网站加了一个人机验证,我们通过selenium会被认为是机器人,就拒绝我们访问!如果用Scrapy 那更不行了。。。好!看我们搞定!

在这里插入图片描述

6.1开发环境

python 3.12.6

谷歌浏览器:131.0.6778.109

#Chrome的驱动chromedriver
https://download.csdn.net/download/Lookontime/90091812

插件:undetected_chromedriver

pip install undetected_chromedriver -i http://pypi.doubanio.com/simple --trusted-host pypi.doubanio.com

6.2修改params.py 文件

#params.py文件
from pydantic import BaseModel
from typing import List, Optional
class FanyiParams(BaseModel):
    query: str
    lang: str = 'en2zh'
    ext_channel: str = 'DuSearch'
    # lang: Optional[str] = 'zh2en'
    # ext_channel: Optional[str] = 'DuSearch'
    
class BiziParams(BaseModel):
    keyboard: str

6.3新增servers类库

  1. 在主目录在新增servers文件夹
  2. servers文件夹下新增__init__.py文件内容为空
  3. servers文件夹下新增seleniumHelper文件夹
  4. seleniumHelper文件夹 新增index.py文件
#index.py
import base64
from io import BytesIO
import os
from pathlib import Path
import re
import time
from PIL import Image

#确保页面加载完成,避免异步调用导致异常
import undetected_chromedriver as uc
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


class seleniumInit:
    def __init__(self):
        options = uc.ChromeOptions()
        options.add_argument('--disable-gpu')
        self.driver = uc.Chrome(
            executable_path="F:/开发源码/python_demo_07/my_venv_3_12_6/Scripts/chromedriver.exe", 
            options=options
        )
        self.keyboard = None
        
    def start_requests(self,keyboard='手机'):
        self.keyboard = keyboard
        # 初始页面只需要加载一次并输入关键词
        url = "https://pic.netbian.com/new/"
        self.driver.get(url)
        
        WebDriverWait(self.driver, 10).until(
            EC.presence_of_element_located((By.NAME, 'keyboard'))
        )
        
        input_box = self.driver.find_element(By.NAME, "keyboard")
        input_box.clear()
        input_box.send_keys(keyboard + Keys.RETURN)

        # 等待页面跳转到搜索结果页
        WebDriverWait(self.driver, 10).until(
            EC.presence_of_element_located((By.CLASS_NAME, 'nextpage'))
        )

        # 从搜索结果开始解析
        self.parse_with_selenium(self.driver.current_url)

    def parse_with_selenium(self, url):
        
        self.driver.get(url)
        
        WebDriverWait(self.driver, 10).until(
            EC.presence_of_element_located((By.XPATH, "//a[@target='_blank']"))
        )
        next_page_element = self.driver.find_element(By.XPATH, "//li[@class='nextpage']/a")
        next_page_href = next_page_element.get_attribute('href')
        a_list = self.driver.find_elements(By.XPATH, "//a[@target='_blank']")
        hrefs = [a.get_attribute('href') for a in a_list if a.get_attribute('href')]

        for href in hrefs:
            if href.startswith('https://pic.netbian.com/tupian'):
                print(f"发现链接: {href}")
                self.get_img(href)

        # 处理下一页
        try:
            if next_page_href:
                self.parse_with_selenium(next_page_href)
        except Exception:
            print("没有下一页")

    def get_img(self, url):
        self.driver.get(url)
        WebDriverWait(self.driver, 10).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, 'a#img img'))
        )
        img_element = self.driver.find_element(By.CSS_SELECTOR, 'a#img img')
        img_src = img_element.get_attribute('src')
        
        if img_src:
            # 确保 URL 是完整的
            img_url = img_src if img_src.startswith('http') else f"https://pic.netbian.com{img_src}"
            print('准备下载图片:', img_url)
            # 下载并保存图片

            # 设置保存图片的文件夹路径
            save_folder = f"F:/ImageFiles/{self.keyboard}/"  # 你可以根据需要修改这个路径
            if not os.path.exists(save_folder):
                os.makedirs(save_folder)  # 如果文件夹不存在,则创建
            
            # 合成完整的文件路径
            file_name = img_url.split('/')[-1]
            file_path = os.path.join(save_folder, file_name)
            js = "let c = document.createElement('canvas');let ctx = c.getContext('2d');" \
                    "let img  = document.querySelector('a#img img'); /*找到图片*/ " \
                    "c.height=img.naturalHeight;c.width=img.naturalWidth;" \
                    "ctx.drawImage(img, 0, 0,img.naturalWidth, img.naturalHeight);" \
                    "let base64String = c.toDataURL();return base64String;"
      
            base64_str = self.driver.execute_script(js)
            img = self.base64_to_image(base64_str)
            print("最终img",img)
            # 转换为RGB模式(如果是RGBA)
            if img.mode == 'RGBA':
                img = img.convert('RGB')
            img.save(file_path, format='JPEG')
            
            time.sleep(6)
            print(f'图片已保存: {file_name}')

    def base64_to_image(self,base64_str):
        base64_data = re.sub('^data:image/.+;base64,', '', base64_str)
        byte_data = base64.b64decode(base64_data)
        image_data = BytesIO(byte_data)
        img = Image.open(image_data)
        return img

6.4 修改fanyi.py文件添加一个接口

#fanyi.py
from fastapi import APIRouter, HTTPException

from .params import *
#确保页面加载完成,避免异步调用导致异常
import undetected_chromedriver as uc
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from servers.seleniumHelper.index import seleniumInit

router = APIRouter()


@router.post("/baidu_fanyi")
def baidu_fanyi(params:FanyiParams):
    try:
        # 设置 无头模式
        options = uc.ChromeOptions()
        
        # 添加无头模式选项
        options.add_argument('--headless')
        # 添加其他必要参数
        options.add_argument('--disable-gpu')  # 禁用 GPU
        options.add_argument('--no-sandbox')  # 避免沙盒模式问题(可选)
        options.add_argument('--disable-dev-shm-usage')  # 防止共享内存问题(可选)
        options.add_argument('--window-size=1920,1080')  # 设置窗口大小
        options.add_argument('--disable-blink-features=AutomationControlled')  # 禁用自动化控制检测
        browser = uc.Chrome(
            executable_path="F:/开发源码/python_demo_07/my_venv_3_12_6/Scripts/chromedriver.exe", 
            options=options
        )
        browser.get(f'https://fanyi.baidu.com/mtpe-individual/multimodal?query={params.query}&lang={params.lang}&ext_channel={params.ext_channel}')

        # 等待页面中某个元素加载完成
        WebDriverWait(browser, 10).until(
            EC.presence_of_element_located((By.ID, 'trans-selection'))
        )

        fanyi = browser.find_element(By.ID, "trans-selection")
        fanyi_text = fanyi.text
        print("翻译结果",fanyi_text)
        browser.close() 
        # html = browser.page_source  # 获取完整 HTML 内容  
        return fanyi_text
    except Exception as e:
        print(f"发生错误: {e}")
        return {"error": "无法获取翻译结果"}

#  2.爬取壁纸
@router.post("/iciba_fanyi")
def iciba_fanyi(params:BiziParams):
    sInit = seleniumInit()
    sInit.start_requests(params.keyboard)

    return "爬取完成"

总结下这个网站我是看csdn上有个大佬爬过,所以我也就试试用来测试技术,技术文章仅用于学习与研究目的,不得用于违法行为,如需要壁纸请购买,支持正版,而且正版的壁纸清晰度很高,这部分不能是爬取到的。

但是发现这个网站加了机器人 加了图片请求转换,等待,所以开发的思路就是不能用原生selenium,否则机器人检测我们过不去,等我们千辛万苦绕过机器人时,发现请求图片被后端进行转换了并不能给你图片信息,这个时候就需要用js来实现复制图片。

代码地址:

https://download.csdn.net/download/Lookontime/90097745

七.总结

Python 进阶中的selenium就介绍到这里,再次声明文章只是为了研究selenium技术。

创作整理不易,请大家多多关注 多多点赞,有写的不对的地方欢迎大家补充,我来整理,再次感谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/934510.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

day10性能测试(2)——Jmeter

【没有所谓的运气&#x1f36c;&#xff0c;只有绝对的努力✊】 目录 1、LoadRunner vs Jmeter 1.1 LoadRunner 1.2 Jmeter 1.3 对比小结 2、Jmeter 环境安装 2.1 安装jdk 2.2 安装Jmeter 2.3 小结 3、Jmeter 文件目录结构 4、Jmeter默认配置修改 5、Jmeter元件、组…

架构15-服务网格

零、文章目录 架构15-服务网格 1、透明通信的涅槃 &#xff08;1&#xff09;服务网格 概念 服务网格是一种处理程序间通信的基础设施&#xff0c;主要由数据平面和控制平面组成。它通过边车代理和控制程序管理程序间的通信&#xff0c;弥补了容器编排系统对分布式应用细粒…

day08 接口测试(4)知识点完结!!

【没有所谓的运气&#x1f36c;&#xff0c;只有绝对的努力✊】 目录 1、postman读取外部数据文件&#xff08;参数化&#xff09; 1.1 数据文件简介 1.2 导入外部数据文件 1.2.1 csv文件 1.2.2 导入 json文件 1.3 读取数据文件数据 1.4 案例 1.5 生成测试报告 2、小…

2024年11月HarmonyOS应用开发者高级认证全新题库

注意事项&#xff1a;切记在考试之外的设备上打开题库进行搜索&#xff0c;防止切屏三次考试自动结束&#xff0c;题目是乱序&#xff0c;每次考试&#xff0c;选项的顺序都不同&#xff0c;作者已于2024年11月22日又更新了一波题库&#xff0c;题库正确率99%&#xff01; 新版…

【Python网络爬虫 常见问题汇总】

目录 1. 爬取图片出现403解决办法&#xff1a;设置请求头中的Referer字段 2.关于干坏事的问题后续不定期更新 欢迎共同探讨学习进步 1. 爬取图片出现403 问题出自案例9&#xff0c;已解决。 【Python网络爬虫笔记】9- 抓取优美图库高清壁纸 当在爬取图库图片时遇到 403 错误…

《探索形象克隆:科技与未来的奇妙融合》

目录 一、什么是形象克隆 二、形象克隆的技术原理 三、形象克隆的发展现状 四、形象克隆的未来趋势 五、形象克隆的应用场景 六、形象克隆简单代码案例 Python 实现数字人形象克隆 Scratch 实现角色克隆效果&#xff08;以猫为例&#xff09; JavaScript 实现 Scratc…

Mac软件推荐

Mac软件推荐 截图SnipasteXnipBob 快捷启动Raycast 系统检测Stats 解压缩The UnarchiverKeka&#xff08;付费&#xff09; 视频播放IINA 视频下载Downie&#xff08;付费&#xff09; 屏幕刘海TopNotchMediaMate&#xff08;付费&#xff09;NotchDrop&#xff08;付费&#x…

Linux——linux系统移植

创建VSCode工程 1、将NXP官方的linux内核拷贝到Ubuntu 2、解压缩tar -vxjf linux-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2 NXP官方开发板Linux内核编译 1、将.vscode文件夹复制到NXP官网linux工程中&#xff0c;屏蔽一些不需要的文件 2、编译NXP官方EVK开发板对应的Linux系统…

TikTok运营选什么网络?要用原生IP吗?

不管是跨境电商运营还是个人IP打造&#xff0c;TikTok都是必不可少的一个大流量平台。但运营TikTok必然要面临网络问题&#xff0c;如果没有妥当的解决方案&#xff0c;不仅难以获取流量&#xff0c;还可能面临封号的风险。因此&#xff0c;选择可靠的网络并合理使用是非常重要…

Spring 基础

什么是 Spring 框架? Spring 是一款开源的轻量级 Java 开发框架&#xff0c;旨在提高开发人员的开发效率以及系统的可维护性。 我们一般说 Spring 框架指的都是 Spring Framework&#xff0c;它是很多模块的集合&#xff0c;使用这些模块可以很方便地协助我们进行开发&#…

Redis篇-5--原理篇4--Lua脚本

1、概述 Redis 支持使用 Lua 脚本来执行复杂的操作&#xff0c;这为 Redis 提供了更强的灵活性和性能优化能力。通过 Lua 脚本&#xff0c;你可以在服务器端执行一系列命令&#xff0c;而不需要多次往返客户端与服务器之间&#xff0c;从而减少了网络延迟并提高了效率。此外&a…

【数据库】关系代数和SQL语句

一 对于教学数据库的三个基本表 学生S(S#,SNAME,AGE,SEX) 学习SC(S#,C#,GRADE) 课程(C#,CNAME,TEACHER) &#xff08;1&#xff09;试用关系代数表达式和SQL语句表示&#xff1a;检索WANG同学不学的课程号 select C# from C where C# not in(select C# from SCwhere S# in…

【git】--- 通过 git 和 gitolite 管理单仓库的 SDK

在编程的艺术世界里,代码和灵感需要寻找到最佳的交融点,才能打造出令人为之惊叹的作品。而在这座秋知叶i博客的殿堂里,我们将共同追寻这种完美结合,为未来的世界留下属于我们的独特印记。【git】--- 通过 git 和 gitolite 管理单仓库的 SDK 开发环境一、安装配置 gitolite二…

HDFS高可用模式安装部署

实验步骤 将ZooKeeper集群模式启动获取安装包 安装包在本地&#xff1a;通过XFTP等工具将安装包上传到虚拟机中安装包在网络&#xff1a; 虚拟机可以访问互联网虚拟机无法访问互联网解压缩安装包将解压出来安装目录重命名配置环境变量刷新环境变量&#xff0c;使新增的环境变量…

mysql程序介绍,选项介绍(常用选项,指定选项的方式,特性),命令介绍(查看,部分命令),从sql文件执行sql语句的两种方法

目录 mysql程序 介绍 选项 介绍 常用选项 指定选项的方式 ​编辑配置文件 环境变量 选项特性 指定选项 选项名 选项值 命令 介绍 查看客户端命令 tee/notee prompt source system help contents 从.sql文件执行sql语句 介绍 方式 source 从外部直接导入…

PDF处理的创新工具:福昕低代码平台尝鲜实现PDF2word功能

在当今数字化时代&#xff0c;PDF文件的处理和管理变得越来越重要。福昕低代码平台是新发布的一款创新的工具&#xff0c;旨在简化PDF处理和管理的流程。通过这个平台&#xff0c;用户可以通过简单的拖拽界面上的按钮&#xff0c;轻松完成对Cloud API的调用工作流&#xff0c;而…

【C++】C++11(统一列表初始化、声明、右值引用)

&#x1f308;个人主页&#xff1a;秦jh_-CSDN博客&#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/qinjh_/category_12575764.html?spm1001.2014.3001.5482 ​ 目录 C11简介 统一的列表初始化 &#xff5b;&#xff5d;初始化 std::initializer_list 声明 …

对比九种MySQL高可用方案

文章目录 一、读写分离如何在业务中落地什么时候需要读写分离MySQL 主从复制技术--binlog日志主从复制过程存在主从复制延时问题主从同步延迟的解决方案主从复制如何避免丢数据总结二、对比九种MySQL高可用方案组复制、半同步复制、异步复制主从复制方案选型-异步复制主从复制方…

再用RNN神经网络架构设计生成式语言模型

上一篇&#xff1a;《用谷歌经典ML方法方法来设计生成式人工智能语言模型》 序言&#xff1a;市场上所谓的开源大语言模型并不完全开源&#xff0c;通常只提供权重和少量工具&#xff0c;而架构、训练数据集、训练方法及代码等关键内容并未公开。因此&#xff0c;要真正掌握人…

httprunner实践样例

目录 1. 安装 HTTPRunner 2. 基本概念和目录结构 3. 编写一个 HTTPRunner 测试用例&#xff08;YAML 示例&#xff09; 4. 运行测试用例 5. 使用 Python 编写测试用例 6. 运行 Python 测试用例 7. 集成测试报告 8. 高级用法&#xff1a;集成环境变量、外部数据 9. 集成…