有很多网站,例如淘宝,它上面的很多页面 的数据是由JavaScript生成的,而不是原始HTML代码,而且还有很多ajax获取的数据,甚至有些数据是加密的。当我们使用普通的requests来处理时,需要分析很多的js代码,此时非常困难,所以我们就用selenium来解决。
selenium框架的简单介绍
selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,利用它可以控制浏览器执行特定的动作,例如点击、下拉、输入内容等
selenium文档地址:https://selenium-python.readthedocs.io/
# 在安装过程中最好限定框架版本为4.9.1pip install selenium==4.9.1 -i https://pypi.tuna.tsinghua.edu.cn/simple
安装完selenium后,还需要安装使用selenium控制的浏览器需要的驱动。
谷歌驱动下载地址:https://googlechromelabs.github.io/chrome-for-testing/#stable
驱动下载完成后将文件移动到系统环境变量中:
● MacOS:将文件移动到/usr/local/bin目录
● Windows:将文件移动到miniconda3安装目录
编写以下代码,验证是否能正常运行:
from selenium import webdriverbrowser = webdriver.Chrome()
如果可以正常打开浏览器则配置成功。
除了可以配置谷歌浏览器之外也可以配置火狐浏览器,配置方式与谷歌浏览器大致相同。
火狐驱动下载地址:https://github.com/mozilla/geckodriver/releases
from selenium import webdriver# 获取要操作的浏览器驱动对象(直白点说,这个对象可以控制浏览器)browser = webdriver.Chrome()# 加载指定的页面browser.get("http://www.baidu.com")# 截屏browser.save_screenshot("百度首页.png")
import timefrom selenium import webdriverfrom selenium.webdriver.common.by import By# 获取要操作的浏览器驱动对象browser = webdriver.Chrome()# 加载指定的页面browser.get("http://www.baidu.com")# 获取指定的元素browser.find_element(By.ID, 'kw').send_keys('java')# 延时,以便看清楚要进行的操作time.sleep(2)# 点击 "百度一下"browser.find_element(By.ID, 'su').click()
import timefrom selenium import webdriver# 获取要操作的浏览器驱动对象browser = webdriver.Chrome()# 加载指定的页面browser.get("http://www.baidu.com")# 查看访问的页面源代码print(browser.page_source)# 查看cookieprint(browser.get_cookies())# 查看经过处理之后,本页面最后显示的url,如果有302的话,那么就是302之后的urlprint(browser.current_url)
import timefrom selenium import webdriver# 创建浏览器browser = webdriver.Chrome()# 打开百度browser.get("http://www.baidu.com")time.sleep(3)# 打开京东browser.get("https://jd.com")time.sleep(3)# 关闭browser.close()
import timefrom selenium import webdriverbrowser = webdriver.Chrome()# 打开淘宝browser.get("http://login.taobao.com")time.sleep(3)# 打开搜狗: 执行js脚本打开新的标签页js = "window.open('http://www.sogou.com')"browser.execute_script(js)
import timefrom selenium import webdriverbrowser = webdriver.Chrome()# 打开淘宝browser.get("http://login.taobao.com")time.sleep(3)# 打开搜狗js = "window.open('http://www.sogou.com')"browser.execute_script(js)time.sleep(3)# 切换到第1个标签页browser.switch_to.window(browser.window_handles[0])time.sleep(1)browser.switch_to.window(browser.window_handles[1])time.sleep(1)# 关闭第2个标签页browser.close()time.sleep(1)# 切换到第1个标签页browser.switch_to.window(browser.window_handles[0])# 关闭第1个标签页browser.close()
import timefrom selenium import webdriver# 获取要操作的浏览器驱动对象browser = webdriver.Chrome()# 加载指定的页面browser.get("http://www.baidu.com")# 为了演示,浏览器打开后关闭的效果,要先延时一会time.sleep(3)# 关闭当前页面(当浏览器只有1个页面时,此操作会让浏览器退出)browser.close()# 让浏览器退出(如果用selenium打开了很多标签页的情况下)browser.quit()
多个标签页切换顺序混乱的问题
window_handles列表保存了根据顺序打开的标签页句柄,但是在某些特殊的情况下标签页顺序和列表句柄元素顺序不一致,比如网络速度或页面响应速度的不同会导致实际打开页面的顺序和预期不同。所以在代码中不能完全依赖列表索引的方式完成页面切换。
解决方式如下:
import timefrom selenium import webdriverbrowser = webdriver.Chrome()# 打开淘宝browser.get("http://login.taobao.com")time.sleep(3)# 打开搜狗js = "window.open('http://www.sogou.com')"browser.execute_script(js)time.sleep(3)# 打开必应js = "window.open('http://www.bing.com')"browser.execute_script(js)time.sleep(3)# 打印当前所有标签页的窗口句柄print(browser.window_handles)# 打印所有句柄对应的标签页名称for handle in browser.window_handles:browser.switch_to.window(handle)print("句柄: {},页面标题: {}".format(handle, browser.title))for handle in browser.window_handles:browser.switch_to.window(handle)# 通过页面标题或URL来定位if ("搜狗" in browser.title) or ("sogou.com" in browser.current_url):print("已切换到搜狗页面:", handle)time.sleep(2)browser.close() # 关闭搜狗标签页elif ("必应" in browser.title) or ("bing.com" in browser.current_url):print("已切换到必应页面:", handle)time.sleep(2)else:print('已切换到淘宝页面:', handle)time.sleep(2)print(browser.window_handles)browser.quit()
元素定位的基本使用方式
在定位元素时,需要借助selenium框架提供的定位工具来进行元素定位。元素定位工具导入路径如下:
from selenium.webdriver.common.by import By
为了能够点击某个按钮,此时我们就需要准确无误地定位到需要的元素。元素定位主要分为以下两种:
● 单个节点(返回是一个对象)
○ find_element(By.ID, '定位规则')
○ find_element(By.NAME, '定位规则')
○ find_element(By.XPATH, '定位规则')
○ find_element(By.LINK_TEXT, '定位规则')
○ find_element(By.PARTIAL_LINK_TEXT, '定位规则')
○ find_element(By.TAG_NAME, '定位规则')
○ find_element(By.CLASS_NAME, '定位规则')
○ find_element(By.CSS_SELECTOR, '定位规则')
● 多个节点(返回是一个列表)
○ find_elements(By.ID, '定位规则')
○ find_elements(By.NAME, '定位规则')
○ find_elements(By.XPATH, '定位规则')
○ find_elements(By.LINK_TEXT, '定位规则')
○ find_elements(By.PARTIAL_LINK_TEXT, '定位规则')
○ find_elements(By.TAG_NAME, '定位规则')
○ find_elements(By.CLASS_NAME, '定位规则')
○ find_elements(By.CSS_SELECTOR, '定位规则')
案例:获取单个节点
import timefrom selenium import webdriverfrom selenium.webdriver.common.by import By# 获取浏览器驱动对象browser = webdriver.Chrome()# 打开指定URLbrowser.get('http://news.baidu.com/')# 定位搜索框ret = browser.find_element(By.ID, 'ww')# ret = browser.find_element(By.CSS_SELECTOR, '#ww') # 查询id为ww# ret = browser.find_element(By.CSS_SELECTOR, '.word') # 查询class为word# ret = browser.find_element(By.XPATH, "//input[@class='word']")print(ret)time.sleep(3)browser.quit()
import timefrom selenium import webdriverfrom selenium.webdriver.common.by import By# 获取浏览器驱动对象browser = webdriver.Chrome()# 打开指定URLbrowser.get('https://movie.douban.com/top250')# 定位25个电影信息ret = browser.find_elements(By.CSS_SELECTOR, '.item') # 查询class为itemprint(ret)ret = browser.find_elements(By.XPATH, "//*[@class='item']")print(ret)time.sleep(3)browser.quit()
注意点
find_element和find_elements的区别是:前者返回一个对象,后者返回一个列表
by_link_text和by_partial_link_text的区别:前者匹配全部文本,后者包含某个文本
提取标签内容与属性值
find_element仅仅能够获取元素,不能够直接获取其中的数据,如果需要获取数据需要使用以下方法:
● 获取文本:element.text
● 获取属性值:element.get_attribute("href")
import timefrom selenium import webdriverfrom selenium.webdriver.common.by import By# 获取浏览器驱动对象browser = webdriver.Chrome()# 打开指定URLbrowser.get('https://www.douban.com')# 定位h1标签ret = browser.find_elements(By.TAG_NAME, "h1")print(ret[0].text)# 输出:豆瓣ret = browser.find_elements(By.LINK_TEXT, "下载豆瓣 App")print(ret[0].get_attribute("href"))# 输出:https://www.douban.com/doubanapp/app?channel=nimingyetime.sleep(3)browser.quit()
处理cookie
通过driver.get_cookies()能够获取所有的cookie
cookie转dict
from selenium import webdriverbrowser = webdriver.Chrome()browser.get("http://www.baidu.com")cookie_list = browser.get_cookies()print(cookie_list)# 整理为requests等需要的字典方式,因为浏览器在发送新请求时携带的cookie只有name、value# 所以此时提取的也只有name、value,其他的不需要cookie_dict = {x["name"]: x["value"] for x in cookie_list}print(cookie_dict)# 关闭页面browser.close()
# 删除一条cookiebrowser.delete_cookie("CookieName")# 删除所有的cookiebrowser.delete_all_cookies()
添加cookie
注意点:添加的字段必须包含name和value,name是cookie信息中的键,value是cookie中的值
# 添加cookie与获取指定cookiefrom selenium import webdriverbrowser = webdriver.Chrome()browser.get('https://www.baidu.com')browser.add_cookie({'name': 'username', 'value': '安娜'})browser.add_cookie({'name': 'gender', 'value': '女'})cookie_list = browser.get_cookies()cookie_dict = {x["name"]: x["value"] for x in cookie_list}print(cookie_dict)print(browser.get_cookie('username')) # 获取指定cookieprint(browser.get_cookie('gender'))browser.quit()
页面等待
如果网站采用了动态html技术,那么页面上的部分元素出现时间便不能确定,这个时候就可以设置一个等待时间,强制要求在时间内出现,否则报错。
获取京东网站的搜索输入框
presence_of_element_located:判定符合查询条件的一个元素是否存在
presence_of_elements_located:判断符合查询条件的所有元素是否存在
import timefrom selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as EC# 创建浏览器驱动对象browser = webdriver.Chrome()# 窗口最大化: 保证页面元素不会被其他元素遮挡browser.maximize_window()# 创建等待操作对象wait_ob = WebDriverWait(browser, 10)# 加载urlbrowser.get("http://jd.com")# 等待条件满足search_input = wait_ob.until(EC.presence_of_element_located((By.ID, 'key')))# 输入内容search_input.send_keys("Mac Pro")# 点击查询search_button = wait_ob.until(EC.presence_of_element_located((By.XPATH, '//*[@id="search"]/div/div[2]/button')))search_button.click()# 延时等待以便于观察页面变化time.sleep(10)# 退出browser.quit()
页面的前进与后退
import timefrom selenium import webdriverbrowser = webdriver.Chrome()browser.get("http://jd.com")time.sleep(2)browser.get("http://ganji.com")time.sleep(2)# 后退browser.back()time.sleep(1)# 前进browser.forward()time.sleep(1)browser.quit()
动作链
在selenium中,动作链是一种用于模拟用户交互的技术。它允许你执行一系列连续的动作,例如鼠标移动、鼠标点击、按键操作等。通过使用动作链,你可以模拟用户在网页上的复杂交互操作,例如拖拽元素、悬停、双击等。
from selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver import ActionChainsbrowser = webdriver.Chrome()url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'browser.get(url)log = browser.find_element(By.XPATH, '//div[@id="iframewrapper"]/iframe')browser.switch_to.frame(log)source = browser.find_element(By.CSS_SELECTOR, '#draggable')target = browser.find_element(By.CSS_SELECTOR, '#droppable')actions = ActionChains(browser)actions.drag_and_drop(source, target)actions.perform()
案例:登录网易邮箱
import timefrom selenium import webdriverfrom selenium.webdriver.common.by import Byclass WyMail:def __init__(self):self.driver = webdriver.Chrome()def open_email(self, url):self.driver.get(url)time.sleep(1)def login_email(self, email, password):iframe = self.driver.find_element(By.XPATH, '//div[@id="loginDiv"]/iframe[@scrolling = "no"]')# 登录表单为一个子页面, 需要切入到当前这个子页面中self.driver.switch_to.frame(iframe)self.driver.find_element(By.XPATH, '//input[@name="email"]').send_keys(email)self.driver.find_element(By.XPATH, '//div[@class="u-input box"]//input[@name="password"]').send_keys(password)self.driver.find_element(By.XPATH, './/*[@id="dologin"]').click()def close(self):time.sleep(10)self.driver.quit()if __name__ == '__main__':email = WyMail()email.open_email('https://mail.163.com/')email.login_email('wt_poppies@163.com', 'wt199486')email.close()
页面滚动
大部分网站数据是动态数据,需要触发ajax请求后才能在页面中进行数据渲染,触发ajax请求的方式之一就是页面滑动,例如爱奇艺、今日头条等网站。
import timefrom selenium import webdriverbrowser = webdriver.Chrome()browser.get('https://36kr.com/')for num in range(1, 10):# 绝对位置# browser.execute_script(f'window.scrollTo(0, {num * 700})')# 相对位置browser.execute_script(f'window.scrollBy(0, {num * 700})')time.sleep(1)
绕过检测
在一些网站当中有专门对浏览器驱动程序进行检测,例如:https://bot.sannysoft.com/
我们可以谷歌浏览器配置项来隐藏浏览器驱动信息,代码如下:
import timefrom selenium import webdriver# 创建浏览器配置对象options = webdriver.ChromeOptions()options.add_argument('--disable-blink-features=AutomationControlled')browser = webdriver.Chrome(options=options)browser.get('https://bot.sannysoft.com/')time.sleep(10)browser.quit()
import timefrom selenium import webdriver# 浏览器配置加载options = webdriver.ChromeOptions()# 禁止图片加载prefs = {"profile.managed_default_content_settings.images": 2}options.add_experimental_option('prefs', prefs)# 设置UAuser_agent = 'abc'options.add_argument(f'user-agent={user_agent}')# 隐藏开发者警告options.add_experimental_option('useAutomationExtension', False)options.add_experimental_option('excludeSwitches', ['enable-automation'])# 设置代理options.add_argument("--proxy-server=http://127.0.0.1:7890")# 初始化浏览器对象并加载自定义配置browser = webdriver.Chrome(options=options)browser.get('https://www.baidu.com')# 程序休眠以便观察浏览器中的参数设置time.sleep(100)
selenium中的异常处理
在selenium框架中自定义了一些异常类,可以使用框架定义的异常类进行异常捕获。
from selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.common.exceptions import NoSuchElementExceptionbrowser = webdriver.Chrome()try:browser.find_element(By.ID, 'hello')except NoSuchElementException:print('No Element')finally:browser.close()
import timefrom random import randintfrom pymongo import MongoClientfrom selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.common.exceptions import NoSuchElementExceptionclass WpShop:mongo_client = MongoClient()collection = mongo_client['py_spider']['wp_shop']# 创建浏览器配置对象options = webdriver.ChromeOptions()# 屏蔽图片prefs = {"profile.managed_default_content_settings.images": 2}options.add_experimental_option('prefs', prefs)# 驱动配置browser = webdriver.Chrome(options=options)# cookies信息cookies = {"mars_cid": "1730106769949_4ed705c897904ab6da6ed2df7c05b3fe","mars_pid": "0","vip_address": "%257B%2522pid%2522%253A%2522104103%2522%252C%2522cid%2522%253A%2522104103101%2522%252C%2522pname%2522%253A%2522%255Cu6e56%255Cu5357%255Cu7701%2522%252C%2522cname%2522%253A%2522%255Cu957f%255Cu6c99%255Cu5e02%2522%257D","vip_province": "104103","vip_province_name": "%E6%B9%96%E5%8D%97%E7%9C%81","vip_city_name": "%E9%95%BF%E6%B2%99%E5%B8%82","vip_city_code": "104103101","vip_wh": "VIP_HZ","smidV2": "20241028171250025f8fa5509f7d38e275ae812288691700fc76827844722a0","VipRUID": "469642189","VipUID": "b4fcb7035781600c26fa0fd1f5ce4581","VipRNAME": "ph_*****************************739","pc_fdc_area_id": "104103101","pc_fdc_source_ip": "1","VipDFT": "0","vip_ipver": "31","user_class": "b","VipUINFO": "luc%3Ab%7Csuc%3Ab%7Cbct%3Ac_new%7Chct%3Ac_new%7Cbdts%3A0%7Cbcts%3A0%7Ckfts%3A0%7Cc10%3A0%7Crcabt%3A0%7Cp2%3A0%7Cp3%3A1%7Cp4%3A0%7Cp5%3A1%7Cul%3A3105","mst_area_code": "104104","visit_id": "E126929EE78BFFA527BA00E1DF14EADE","VIP_QR_FIRST": "1","vip_access_times": "%7B%22list%22%3A4%7D","vipshop_passport_src": "https%3A%2F%2Fcategory.vip.com%2Fsuggest.php%3Fkeyword%3D%25E7%2594%25B5%25E8%2584%2591%26ff%3D235%257C12%257C1%257C1%26tfs_url%3D%252F%252Fmapi-pc.vip.com%252Fvips-mobile%252Frest%252Fshopping%252Fpc%252Fsearch%252Fproduct%252Frank","_jzqco": "%7C%7C%7C%7C%7C1.132200.1730106770684.1733379498656.1733899693050.1733379498656.1733899693050.0.0.0.5.5","PASSPORT_ACCESS_TOKEN": "A1E6FBB16FE08B779FBC0584A6E6BFB6C216BCA5","VipLID": "0%7C1733899726%7C36a609","VipDegree": "D1","mars_sid": "003a0190be16c7096355fdc127695897","sfl_d": "0",".thumbcache_f65dad1092aa9e66c73b4823b4493a2f": "XyVkJWUOgfG07LTNryoorllgUzp645alot0AsbsCnY2tLH7/WmW5mimEiatW/KXMZcGu4Wavdc6BbnbmKtPjgw%3D%3D","tfs_fp_token": "BXyVkJWUOgfG07LTNryoorllgUzp645alot0AsbsCnY2tLH7/WmW5mimEiatW/KXMZcGu4Wavdc6BbnbmKtPjgw%3D%3D","tfs_fp_timestamp": "1733900421487","pg_session_no": "1","vip_tracker_source_from": "","waitlist": "%7B%22pollingId%22%3A%22BEBAB3CA-A350-4F61-B240-E50056DA4087%22%2C%22pollingStamp%22%3A1733900428480%7D"}# 发送请求@classmethoddef base(cls):cls.browser.get('https://category.vip.com/suggest.php?keyword=%E7%94%B5%E8%84%91&ff=235|12|1|1')for key, value in cls.cookies.items():cookie_dict = {'name': key, 'value': value}cls.browser.add_cookie(cookie_dict)# 页面刷新cls.browser.refresh()time.sleep(randint(1, 3))# 页面滚动@classmethoddef drop_down(cls):for i in range(1, 12):js_code = f'document.documentElement.scrollTop = {i * 1000}'cls.browser.execute_script(js_code)time.sleep(randint(1, 2))# 数据提取@classmethoddef parse_data(cls):cls.drop_down()div_list = cls.browser.find_elements(By.XPATH,'//section[@id="J_searchCatList"]/div[@class="c-goods-item J-goods-item c-goods-item--auto-width"]')for div in div_list:price = div.find_element(By.XPATH,'.//div[@class="c-goods-item__sale-price J-goods-item__sale-price"]').texttitle = div.find_element(By.XPATH,'.//div[2]/div[2]').textitem = {'title': title,'price': price}print(item)cls.save_mongo(item)cls.next_page() # 当前页面获取完成之后需要点击下一页# 数据保存@classmethoddef save_mongo(cls, item):cls.collection.insert_one(item)# 翻页@classmethoddef next_page(cls):try:next_button = cls.browser.find_element(By.XPATH, '//*[@id="J_nextPage_link"]')if next_button:next_button.click()cls.parse_data() # 进入到下一页需要重新解析页面数据else:cls.browser.close()except NoSuchElementException:print('最后一页...')cls.browser.quit()# 启动函数@classmethoddef main(cls):cls.base()cls.parse_data()if __name__ == '__main__':WpShop.main()
DrissionPage与之前学习的Selenium大致相同,也是一个基于Python的页面自动化工具。区别在于DrissionPage既可以控制浏览器也能收发数据包,将两者功能合二为一。功能相对Selenium更强大,语法也更加简洁优雅,具有Selenium基础之后再学习DrissionPage也会更加简单。
官网地址:https://www.drissionpage.cn/
环境安装
操作系统:Windows、Linux和Mac。
Python版本:3.6及以上
支持浏览器:Chromium内核(如Chrome和Edge)
pip install DrissionPage
标签定位
本小节中主要学习如何创建浏览器对象并使用浏览器对象的内置方法完成网站访问以及元素定位。
ele:定位符合条件的单个元素(支持xpath定位以及选择器定位,可以设定timeout超时时间)
官网参数说明:https://www.drissionpage.cn/browser_control/get_elements/find_in_object/#-ele
import timefrom DrissionPage.common import Byfrom DrissionPage import ChromiumPage# 1.创建浏览器对象并访问百度首页page = ChromiumPage()page.get('https://www.baidu.com')# 2.浏览器最大化page.set.window.max()# 3.输入搜索内容# page.ele('xpath://input[@id="kw"]').input('jk')# page.ele('xpath://input[@id="su"]').click()page.ele((By.XPATH, '//input[@id="kw"]')).input('jk')page.ele((By.XPATH, '//input[@id="su"]')).click()time.sleep(5)# 4.关闭浏览器page.quit()
标签等待
本小节主要学习page对象中的eles_loaded方法,用于等待某一个元素或所有元素是否载入到页面中
官网参数说明:https://www.drissionpage.cn/browser_control/waiting/#-waiteles_loaded
from DrissionPage import ChromiumPagepage = ChromiumPage()page.get('https://www.baidu.com')flag = page.wait.eles_loaded('xpath://input[@id="su"]', timeout=2)print(flag)page.quit()
多标签定位
本小节主要学习eles方法定位多标签以及如何使用ele eles对象完成文本数据提取以及属性值的提取
eles:定位符合条件的多个元素,返回值类型为列表
官网参数说明:https://www.drissionpage.cn/browser_control/get_elements/find_in_object/#-eles
from DrissionPage import ChromiumPagepage = ChromiumPage()page.get('https://movie.douban.com/top250')div_list = page.eles("xpath://ol[@class='grid_view']/li/div[@class='item']")for item in div_list:item_dict = dict()movie_name = item.ele('xpath:./div[@class="info"]/div[@class="hd"]//span[1]').textmovie_image = item.ele('xpath:./div[@class="pic"]/a').attr('href')"""attr: 获取指定的属性值attrs: 获取当前标签中的所有属性与值, 返回的数据类型为字典详情: https://www.drissionpage.cn/SessionPage/get_ele_info/#%EF%B8%8F%EF%B8%8F-attrs"""# movie_attr = item.ele('xpath:./div[@class="pic"]/a').attrsprint(movie_name, movie_image)page.quit()
子页面切换
在Selenium中如果需要控制iframe标签中的内容则需要使用switch_to.frame方法,DrissionPage无需操作。
DrissionPage也可以单独对iframe进行操作:https://www.drissionpage.cn/browser_control/iframe
import timefrom DrissionPage.common import Byfrom DrissionPage import ChromiumPagepage = ChromiumPage()page.get('https://www.douban.com')page.ele((By.CLASS_NAME, 'account-tab-account')).click()page.ele((By.ID, 'username')).input('admin')page.ele((By.ID, 'password')).input('admin123')time.sleep(3)page.quit()
import timefrom DrissionPage import ChromiumPageclass MyEmail:def __init__(self):self.page = ChromiumPage()self.url = 'https://mail.163.com/'def login_email(self, email, password):self.page.get(self.url)self.page.ele('xpath://input[@name="email"]').input(email)self.page.ele('xpath://div[@class="u-input box"]//input[@name="password"]').input(password)self.page.ele('xpath://*[@id="dologin"]').click()time.sleep(10)self.page.quit()if __name__ == '__main__':my_email = MyEmail()my_email.login_email('admnin@163.com', 'admin123')
接口监听
本小节主要学习如何使用DrissionPage监听指定的api接口并直接获取接口中的数据
page.listen.start('接口地址'):启动监听器
page.listen.steps(count=你要获取的数据包总数):返回一个可迭代对象,用于for循环,每次循环可从中获取到数据包
<DataPacket>.response.body:获取数据包中的数据
网站请求地址:http://www.ccgp-hunan.gov.cn/page/content/more.jsp?column_code=2
官网参数说明:https://www.drissionpage.cn/browser_control/listener/#-listenstart
from DrissionPage.common import Byfrom DrissionPage import ChromiumPagepage = ChromiumPage()url = 'http://www.ccgp-hunan.gov.cn/page/content/more.jsp?column_code=2'# api监听: 先监听再请求page.listen.start('/mvc/getContentList.do')page.get(url)# 获取api返回的数据(page.listen.steps(): 返回的是一个迭代器)# print(page.listen.steps())# 循环获取数据(count: 监听次数)page_num = 1for item in page.listen.steps(count=8):# 打印监听后返回的对象# print(item)# 打印数据print(f'第{page_num}页(数据类型[{type(item.response.body[0])}]):', item.response.body)# 下一页flag = page.ele((By.LINK_TEXT, '下一页'), timeout=3)if flag:flag.click()else:print('翻页结束...')page.quit()breakpage_num += 1
动作链
本小节主要学习actions动作链对象所提供的内置方法
官网内置方法说明:https://www.drissionpage.cn/browser_control/actions/#%EF%B8%8F-%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95
import timefrom DrissionPage.common import Byfrom DrissionPage import ChromiumPagepage = ChromiumPage()url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'page.get(url)source = page.ele((By.ID, 'draggable'))target = page.ele((By.ID, 'droppable'))page.actions.hold(source).release(target)time.sleep(2)page.quit()
import timefrom DrissionPage.common import Byfrom DrissionPage import ChromiumPageurl = 'https://ynjzjgcx.com/dataPub/enterprise'page = ChromiumPage()page.get(url)# 定位滑动控件并选中控件button = page.ele((By.CLASS_NAME, 'slide-verify-slider-mask-item'))page.actions.hold(button)# 向右移动指定的像素位并释放page.actions.right(150).release()time.sleep(3)page.quit()"""绕过验证码需要专门学习ocr图像识别库"""
SessionPage的使用
SessionPage基于requests进行网络连接,因此可使用requests内置的所有请求方式,包括get()、post()、head()、options()、put()、patch()、delete()。
官网内置方法说明:https://www.drissionpage.cn/SessionPage/visit/
from DrissionPage import SessionPageurl = 'http://www.ccgp-hunan.gov.cn/mvc/getContentList.do'form_data = {'column_code': 2,'title': '','pub_time1': '','pub_time2': '','own_org': 1,'page': 1,'pageSize': 18}page = SessionPage()page.post(url, data=form_data)print(page.user_agent) # 自动构建请求头print(page.response.json())# page.close()
WebPage的使用
WebPage是整合了上面两者的页面对象,既可控制浏览器,又可收发数据包,并且可以在这两者之间共享登录信息。
它有两种工作模式:d模式和s模式。d模式用于控制浏览器,s模式用于收发数据包。WebPage可在两种模式间切换,但同一时间只能处于其中一种模式。
当前对象在新版本中已被作者刻意淡化,不建议使用。
官方文档说明:https://drissionpage.cn/DP32Docs/get_start/basic_concept/#webpage
import timefrom DrissionPage import WebPage# 创建页面对象,初始d模式page = WebPage('d')# 访问百度page.get('http://www.baidu.com')# 定位输入框并输入关键字page.ele('#kw').input('DrissionPage')# 点击"百度一下"按钮page.ele('@value=百度一下').click()# 等待页面加载page.wait.load_start()# 切换到s模式page.change_mode()# 获取所有结果元素results = page.eles('tag:h3')# 遍历所有结果for result in results:# 打印结果文本print(result.text)time.sleep(3)page.quit()
请求头加密的爬虫案例
网站访问地址:https://kaoyan.docin.com/pdfreader/web/#/docin/documents?type=1&keyword=%E5%A4%8D%E8%AF%95%E4%BB%BF%E7%9C%9F%E6%A8%A1%E6%8B%9F
使用requests完成请求.py
import requestsheaders = {"Accept": "application/json, text/plain, */*","Accept-Language": "zh-CN,zh;q=0.9","Cache-Control": "no-cache","Connection": "keep-alive","Content-Type": "application/json","Origin": "https://kaoyan.docin.com","Pragma": "no-cache","Referer": "https://kaoyan.docin.com/","Sec-Fetch-Dest": "empty","Sec-Fetch-Mode": "cors","Sec-Fetch-Site": "cross-site","User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36","X-Application": "Pdfreader.Web","X-Nonce": "02fec55d-8a78-2453-cb18-42f62ef46732","X-Sign": "C0FC7B5784DDE2FD774DD00C6AB89BE5","X-Timestamp": "1733317931","X-Token": "null","X-Version": "V2.2","sec-ch-ua": "Google Chrome;v=131, Chromium;v=131, Not_A Brand;v=24","sec-ch-ua-mobile": "?0","sec-ch-ua-platform": "macOS"}url = "https://www.handebook.com/api/web/document/list"json_data = {"SearchType": 0,"SearchKeyword": "复试仿真模拟","DocumentType": " ","UniversityCode": "","MajorCode": "","ExamSubjectList": [],"PageIndex": 1,"PageSize": 30}response = requests.post(url, headers=headers, json=json_data)print(response.json())
import pymongofrom DrissionPage import WebPagefrom DrissionPage.common import Byclass DouDing:mongo_client = pymongo.MongoClient()def __init__(self):self.url = 'https://kaoyan.docin.com/pdfreader/web/#/docin/documents?type=1&keyword=%E5%A4%8D%E8%AF%95%E4%BB%BF%E7%9C%9F%E6%A8%A1%E6%8B%9F'# self.page = WebPage(mode='d') # mode为设置session模式或者driver模式, 默认为driverself.page = WebPage()def get_info(self):self.page.listen.start('/api/web/document/list')self.page.get(self.url)for item in self.page.listen.steps(count=20):# print(item)self.parse_info(item.response.body)# 翻页self.page.ele((By.CLASS_NAME, 'btn-next'), timeout=3).click()self.page.quit()def parse_info(self, info):for temp in info['Data']['DocumentInfos']:item = dict()item['DocumentGuid'] = temp['DocumentGuid']item['DocumentName'] = temp['DocumentName']item['DocumentPrice'] = temp['DocumentPrice']self.save_info(item)def save_info(self, info_dict):collection = self.mongo_client['py_spider']['dou_ding']collection.insert_one(info_dict)print('保存成功:', info_dict)if __name__ == '__main__':dou_ding = DouDing()dou_ding.get_info()
文件下载
DrissionPage内置下载器,无需手动构建open()文件对象
官网说明:https://www.drissionpage.cn/download/intro
import osfrom DrissionPage import SessionPageurl = 'https://www.lpbzj.vip/allimg'page = SessionPage()page.get(url)element_div = page.s_eles("xpath://div[@id='posts']")[0]detail_url_list = element_div.s_eles("xpath:.//div[@class='img']/a")save_path = './美女写真/'os.makedirs(save_path, exist_ok=True) # 确保保存目录存在for detail_url in detail_url_list:page.get(detail_url.attr('href'))div_element = page.s_eles("xpath://div[@class='article-content clearfix']")[0]image_url_list = div_element.s_eles("xpath:.//img")for image_url in image_url_list:img_src = image_url.attr('src')# 同步下载# res = page.download(img_src, save_path)# print('task status:', res)# 添加下载任务并发下载page.download.add(img_src, save_path)print(f"Downloading image from: {img_src}")
项目实战
唯品会接口数据抓取
import jsonfrom DrissionPage.common import Byfrom DrissionPage import ChromiumPagepage = ChromiumPage()url = 'https://category.vip.com/suggest.php?keyword=%E7%94%B5%E8%84%91&ff=235%7C12%7C1%7C1&tfs_url=%2F%2Fmapi-pc.vip.com%2Fvips-mobile%2Frest%2Fshopping%2Fpc%2Fsearch%2Fproduct%2Frank&page=1'page.listen.start('vips-mobile/rest/shopping/pc/product/module/list/v2')page.get(url)for item in page.listen.steps():response_body = item.response.bodytry:# 提取 JSON 字符串部分start_index = response_body.find('{')end_index = response_body.rfind('}') + 1json_str = response_body[start_index:end_index]info_dict = json.loads(json_str)for temp in info_dict['data']['products']:shop_info = dict()shop_info['商品名称'] = temp['title']shop_info['商品品牌'] = temp['brandShowName']shop_info['商品价格'] = temp['price']['salePrice']print(shop_info)button = page.ele((By.CLASS_NAME, 'cat-paging-next'), timeout=3)if button:button.click()else:print('爬虫结束...')page.quit()except AttributeError:print('数据为空:', response_body)
from DrissionPage import ChromiumPagepage = ChromiumPage()page.listen.start('api/sns/web/v1/homefeed')page.get('https://www.xiaohongshu.com/explore')while True:js_code = f"document.documentElement.scrollTop = document.documentElement.scrollHeight * {1000}"page.run_js(js_code)# 未获取返回false, 获取则返回列表, 列表元素类型为DataPacketis_api_list = page.listen.wait(count=5, timeout=1)print('数据状态:', is_api_list)if is_api_list:for item in is_api_list:print(item.response.body)
import timefrom DrissionPage import ChromiumPagesearch = str(input("输入关键词:"))content = str(input("输入评论内容:"))page = ChromiumPage()page.get('https://www.xiaohongshu.com/search_result?keyword=' + search + '&source=unknown&type=51')print("网站加载成功!")time.sleep(2)for time_button in range(1, 20): # 下滑多少下 你就改多少下time.sleep(2)page.scroll.to_bottom()print("当前下滑:", time_button, "次,剩余", 20 - time_button, "次后,将会开始抓取数据...")print("全部下滑完毕开始抓取页面的元素链接!")my_list = list()ele = page.eles('.cover ld mask')name_ele = page.eles('.title')for href, name in zip(ele, name_ele):lian = href.linkna = name.textprint(na, lian)my_list.extend(lian.split(','))sums = 0print("本次获取数据:", len(my_list), "条")for like_list in my_list:sums = sums + 1print("序号:", sums, "链接:", like_list)page.get(like_list)time.sleep(1)input_list1 = page.ele('.chat-wrapper').click()input_list2 = page.ele('.content-input').input(content)time.sleep(0.5)button = page.ele('.btn submit').click()print("发送成功:", content, "-")time.sleep(2)print("*" * 30)input("主程序结束...")




