irpas技术客

爬虫解析模块(bs4,selenium)_Generalzy

网络 6407

bs4文档 from bs4 import BeautifulSoup Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。Beautiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。 解析器

解析器使用方法优势劣势Python标准库BeautifulSoup(markup, “html.parser”)Python的内置标准库、执行速度适中 、文档容错能力强Python 2.7.3 or 3.2.2)前的版本中文容错能力差lxml HTML 解析器BeautifulSoup(markup, “lxml”)速度快、文档容错能力强需要安装C语言库lxml XML 解析器BeautifulSoup(markup, “xml”)速度快、唯一支持XML的解析器需要安装C语言库html5libBeautifulSoup(markup, “html5lib”)最好的容错性、以浏览器的方式解析文档、生成HTML5格式的文档速度慢、不依赖外部扩展
初始化 def __init__(self, markup="", features=None, builder=None, parse_only=None, from_encoding=None, exclude_encodings=None, element_classes=None, **kwargs): """Constructor. :param markup: html文本或file-like对象 :param features: 解析器:("lxml","lxml-xml", "html.parser", or "html5lib") """ soup = BeautifulSoup("html","lxml") 获取标签和属性 print(soup.title) #选择title标签。 print(soup.head) #选择head标签 print(soup.p) #选择p标签 print(soup.title.name) #获取title标签名 print(soup.p.attrs['name']) #获取p标签name属性值 print(soup.p['name']) #获取p标签name属性值 print(soup.p.string) #获取p标签内容,该方法只能获取第一个p标签内容 print(soup.head.title.string) #嵌套选择,用点号分割,层层嵌套 print(soup.p.contents) # 获取p标签的子节点及其内容,->list print(soup.p.children) # 获取获取标签的子节点->iter print(soup.p.descendants) # 返回子孙节点(不仅仅是子节点,返回结果为迭代器) print(soup.a.parent) # 返回的是第一个a标签的父节点 print(soup.a.parents) # 返回的是父节点以及祖先节点 print(list(enumerate(soup.a.next_siblings))) #a标签的下一个兄弟节点 print(list(enumerate(soup.a.previous_siblings))) #上一个兄弟 find()和find_all()方法 find_all()方法返回值:所有符合条件的元素列表。find()方法 返回值:返回符合条件的第一个元素。 def find_all(self, name=None, attrs={}, recursive=True, string=None, limit=None, **kwargs): """ :param name: 标签名称,可以为字符串,列表,正则 :param attrs: 标签属性 :param recursive: 递归 :param limit: 限制数量 :kwargs: key=val格式的标签属性,如果是class属性,需要写为class_=val :return: A ResultSet of PageElements. :rtype: bs4.element.ResultSet """ def find(self, name=None, attrs={}, recursive=True, string=None, **kwargs): r = None l = self.find_all(name, attrs, recursive, string, 1, **kwargs) if l: r = l[0] return r

对于返回的Element对象:

tag.text 表示其中的文本内容tag.get(attr) 获取attr属性tag.name 表示标签的名字 其他find_* find_parents() 返回所有祖先节点 find_parent() 返回直接父节点 find_next_siblings() 返回后面所有兄弟节点 find_next_sibling() 返回后面第一个兄弟节点 find_all_next() 返回节点后所有符合条件的节点 find_next() 返回第一个符合条件的节点 find_all_previous() 返回节点后所有符合条件的节点 find_previous() 返回第一个符合条件的节点 select()方法

select()主要是以CSS选择器(selector)的方式寻找元素。如果找到元素,则返回元素列表;否则返回空列表。

标签选择器:直接指定标签名 Soup.select(‘p’):寻找所有<p>标签的元素;Soup.select(‘img’):寻找所有<img>标签的元素Soup.select(‘input[name]’):寻找所有<input>标签且包含name属性的元素; 类(class)选择器:. Soup.select('.name):寻找所有class属性为name的元素; 选择器:# Soup.select('#name):寻找所有id属性为name的元素; 层级选择器: 单层:> Soup.select(‘div.list > ul > li > a’):查找所有class为list的div中的ul里的li标签里面的a标签;多层:空格 Soup.select(‘p #name’):寻找所有<p>标签且id为name的元素 Soup.select(‘p .name’):寻找所有class为name的<p>标签; 小结

大部分情况下,find和find_all方法就可以解决问题

selenium中文文档----------文档

Selenium 是一个自动化测试工具,利用它可以驱动浏览器执行特定的动作,如点击、下拉等操作。

pip install selenium

Selenium 支持非常多的浏览器

from selenium import webdriver # 常用Chrome和Edge browser = webdriver.Chrome() browser = webdriver.Edge() browser = webdriver.Firefox() browser = webdriver.Safari() browser = webdriver.Android() browser = webdriver.Ie() browser = webdriver.Opera() browser = webdriver.PhantomJS() 浏览器驱动 Chrome Chrome找到对应版本的下载即可。Edge Edge找到对应版本下载即可。

可以将浏览器驱动放到selenium库的目录下,这样在初始化browser对象时就可以不用传入参数了或者干脆丢个文件夹下,配置环境变量就行。

验证安装 from selenium import webdriver from time import sleep browser = webdriver.Chrome() # 打开百度 browser.get('https://·') sleep(5) # 使用完关闭 browser.close() 定位方式 <button id="submit" name="submitBtn" class="text-center">提交</button> id:标签ID定位 find_element_by_id("submit") name:标签name属性 find_element_by_name("submitBtn") class name:标签类名字定位 find_element_by_class_name("text-center") tag name:标签名字定位 find_element_by_tag_name("button") link text:链接文本定位 find_element_by_link_text("提交") partial link text:部分链接文本定位 find_element_by_link_text("交") xpath:xpath定位 find_element_by_xpath("//div[@id='csdn-toolbar']/div/div/div[2]/div/div/input[1]") css selector:css选择器定位 方法例子描述.class.toolbar-search-container选择 class = 'toolbar-search-container' 的所有元素#id#toolbar-search-input选择 id = 'toolbar-search-input' 的元素**选择所有元素elementinput选择所有 <input\> 元素element>elementdiv>input选择父元素为 <div\> 的所有 <input\> 元素element+elementdiv+input选择同一级中在 <div\> 之后的所有 <input\> 元素[attribute=value]type='text'选择 type = 'text' 的所有元素
find_element_by_css_selector('#submit') find_element_by_css_selector('html>body>div>div>div>div>div>div>button') 定位一个元素定位多个元素含义find_element_by_idfind_elements_by_id通过元素id定位find_element_by_namefind_elements_by_name通过元素name定位find_element_by_xpathfind_elements_by_xpath通过xpath表达式定位find_element_by_link_textfind_elements_by_link_tex通过完整超链接定位find_element_by_partial_link_textfind_elements_by_partial_link_text通过部分链接定位find_element_by_tag_namefind_elements_by_tag_name通过标签定位find_element_by_class_namefind_elements_by_class_name通过类名进行定位find_elements_by_css_selectorfind_elements_by_css_selector通过css选择器进行定位

注意:高版本的selenium只提供了find_element和find_elements方法,通过什么寻找需要额外传入By参数。

from selenium.webdriver.common.by import By class By: """ Set of supported locator strategies. """ ID = "id" XPATH = "xpath" LINK_TEXT = "link text" PARTIAL_LINK_TEXT = "partial link text" NAME = "name" TAG_NAME = "tag name" CLASS_NAME = "class name" CSS_SELECTOR = "css selector" def find_element(self, by=By.ID, value=None) -> WebElement: pass def find_elements(self, by=By.ID, value=None) -> List[WebElement]: pass 操作标签的一些方法 方法说明set_window_size()设置浏览器的大小back()控制浏览器后退forward()控制浏览器前进refresh()刷新当前页面clear()清除文本send_keys (value)模拟按键输入click()单击元素submit()用于提交表单get_attribute(name)获取元素属性值is_displayed()设置该元素是否用户可见size返回元素的尺寸text获取元素的文本execute_script(js)执行js脚本page_source获取页面源码(js已经加载过了)
from selenium import webdriver from selenium.webdriver.common.by import By edge = webdriver.Edge() # 提交表单 edge.find_element(By.ID, "submit").submit() 浏览器控制(无头等) 修改浏览器窗口大小 def set_window_size(self, width, height, windowHandle: str = 'current') -> None: """ 设置浏览器的长宽 driver.set_window_size(800,600) """

还有一些快捷方式:

def maximize_window(self) -> None: """ 最大化 """ command = Command.W3C_MAXIMIZE_WINDOW self.execute(command, None) def fullscreen_window(self) -> None: """ 全屏 """ self.execute(Command.FULLSCREEN_WINDOW) def minimize_window(self) -> None: """ 最小化 """ self.execute(Command.MINIMIZE_WINDOW) 前进后退

webdriver 提供 back 和 forward 方法来实现页面的后退与前进。

#返回 driver.back() #前进 driver.forward()

焦点:selenium中,弹出新窗口,焦点不会切换过去,会导致找不到新页面的标签。

方法说明current_window_handle获得当前窗口句柄window_handles返回所有窗口的句柄到当前会话switch_to.window()用于切换到相应的窗口,与上一节的switch_to.frame()类似,前者用于不同窗口的切换,后者用于不同表单之间的切换。
# 获取打开的多个窗口句柄 windows = driver.window_handles # 切换到当前最新打开的窗口 driver.switch_to.window(windows[-1]) 鼠标事件(事件链,操作链) 方法说明ActionChains(driver)构造ActionChains对象context_click()执行鼠标悬停操作move_to_element(above)右击double_click()双击drag_and_drop()拖动move_to_element(above)执行鼠标悬停操作context_click()用于模拟鼠标右键操作, 在调用时需要指定元素定位perform()执行所有 ActionChains 中存储的行为,可以理解成是对整个操作的提交动作
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains edge = webdriver.Edge() # 提交表单 edge.maximize_window() # 点击验证码 ActionChains(edge).move_to_element_with_offset(验证码标签,偏移量x,偏移量y).click().perform() # 定位要拖动的元素 source = edge.find_element_by_xpath('xxx') # 定位目标元素 target = edge.find_element_by_xpath('xxx') # 执行拖动动作 ActionChains(edge).drag_and_drop(source, target).perform() 键盘事件 rom selenium.webdriver.common.keys import Keys # 模拟回车键进行跳转(输入内容后) edge.find_element_by_id('xxx').send_keys(Keys.ENTER) 模拟键盘按键说明send_keys(Keys.BACK_SPACE)删除键(BackSpace)send_keys(Keys.SPACE)空格键(Space)send_keys(Keys.TAB)制表键(Tab)send_keys(Keys.ESCAPE)回退键(Esc)send_keys(Keys.ENTER)回车键(Enter)
模拟键盘按键说明send_keys(Keys.CONTROL,‘a’)全选(Ctrl+A)send_keys(Keys.CONTROL,‘c’)复制(Ctrl+C)send_keys(Keys.CONTROL,‘x’)剪切(Ctrl+X)send_keys(Keys.CONTROL,‘v’)粘贴(Ctrl+V)send_keys(Keys.F1…Fn)键盘 F1…Fn
等待 显示等待

显式等待:设置一个超时时间,每个一段时间就去检测一次该元素是否存在,如果存在则执行后续内容,如果超过最大时间(超时时间)则抛出超时异常(TimeoutException)。显示等待需要使用 WebDriverWait,同时配合 until 或 not until 。

WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None) - driver:浏览器驱动 - timeout:超时时间,单位秒 - poll_frequency:每次检测的间隔时间,默认为0.5秒 - ignored_exceptions:指定忽略的异常,如果在调用 until 或 until_not 的过程中抛出指定忽略的异常,则不中断代码,默认忽略的只有 NoSuchElementException 。 ------------------------------------------------------ until(method, message=’ ‘) until_not(method, message=’ ') - method:指定预期条件的判断方法 - message:TimeoutException报错信息 ----------------------------------------------------------------------------- from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions from selenium.webdriver.common.by import By driver = webdriver.Chrome() element = WebDriverWait(driver, 5, 0.5).until(EC.presence_of_element_located((By.ID, 'submitBtn')), message='guys,不是叔找不到,是你程序有Bug!') 方法描述title_is(‘百度一下’)判断当前页面的 title 是否等于预期title_contains(‘百度’)判断当前页面的 title 是否包含预期字符串presence_of_element_located(locator)判断元素是否被加到了 dom 树里,并不代表该元素一定可见visibility_of_element_located(locator)判断元素是否可见,可见代表元素非隐藏,并且元素的宽和高都不等于0visibility_of(element)跟上一个方法作用相同,但传入参数为 elementtext_to_be_present_in_element(locator , ‘百度’)判断元素中的 text 是否包含了预期的字符串text_to_be_present_in_element_value(locator , ‘某值’)判断元素中的 value 属性是否包含了预期的字符串frame_to_be_available_and_switch_to_it(locator)判断该 frame 是否可以 switch 进去,True 则 switch 进去,反之 Falseinvisibility_of_element_located(locator)判断元素中是否不存在于 dom 树或不可见element_to_be_clickable(locator)判断元素中是否可见并且是可点击的staleness_of(element)等待元素从 dom 树中移除element_to_be_selected(element)判断元素是否被选中,一般用在下拉列表element_selection_state_to_be(element, True)判断元素的选中状态是否符合预期,参数 element,第二个参数为 True/Falseelement_located_selection_state_to_be(locator, True)跟上一个方法作用相同,但传入参数为 locatoralert_is_present()判断页面上是否存在 alert
隐式等待

隐式等待是全局性的,即运行过程中,如果元素可以定位到,它不会影响代码运行,但如果定位不到,则它会以轮询的方式不断地访问元素直到元素被找到,若超过指定时间,则抛出异常。

# 等待5s driver.implicitly_wait(5) try: # 触发隐式等待 driver.find_element_by_id('btn') except Exception as e: print(f'叔找不到你要的标签,叔给你报个错:{str(e)}') 强制等待

time.sleep()

iframe

对于内嵌的页面 selenium 是无法直接定位的,需要使用 switch_to.frame() 方法将当前操作的对象切换成 frame/iframe 内嵌的页面。

switch_to.frame() 默认可以用的 id 或 name 属性直接定位,但如果 iframe 没有 id 或 name ,这时就需要使用 xpath 进行定位。

# 1.通过id定位 driver.switch_to.frame('fuck off') # 2.通过name定位 driver.switch_to.frame('fuck off') # 3. 通过xpath定位 iframe_label = driver.find_element_by_xpath('/html/body/fuck/off/iframe') driver.switch_to.frame(iframe_label) 弹窗处理

PS:**的,之前写超星某某通自动评论的脚本,弹窗真心恶心到我了。

JavaScript 有三种弹窗 alert(确认)、confirm(确认、取消)、prompt(文本框、确认、取消)。

方法描述text获取弹窗中的文字accept()接受(确认)弹窗内容dismiss()解除(取消)弹窗send_keys()发送文本至警告框
alert = driver.switch_to.alert alert.accept() 文件操作

对于文件操作,我还是觉得可以先拿到url然后多进程,多线程,协程下载就行

上传 edge.find_element_by_xpath('//*[@name="upload"]').send_keys(file_path) 下载

需要用到浏览器选项,from selenium.webdriver import ChromeOptions

from selenium.webdriver import ChromeOptions prefs = { # 禁止弹窗 'profile.default_content_settings.popups': 0, # 文件下载路径 'download.default_directory': "file_Path" } option = webdriver.ChromeOptions() option.add_experimental_option('prefs', prefs) driver = webdriver.Chrome(options=option) driver.find_element_by_xpath('下载链接').click() # 如果出现非安全需要切换到最新窗口 driver.switch_to.window(driver.window_handles[-1]) # 输入thisisunsafe即可 driver.find_element_by_xpath('./html').send_keys('thisisunsafe') cookies edge.get_cookies:以字典的形式返回当前会话中可见的 cookie 信息。edge.get_cookie(name):返回 cookie 字典中 key == name 的 cookie 信息。edge.add_cookie(cookie_dict):将 cookie 添加到当前会话中edge.delete_cookie(name):删除指定名称的单个 cookie。edge.delete_all_cookies():删除会话范围内的所有 cookie。 关闭操作 quit()关闭所有页面并退出驱动close()关闭当前页面。 下拉框选择操作 from selenium.webdriver.support.select import Select 方法说明select_by_value(“选择值”)select标签的value属性的值select_by_index(“索引值”)下拉框的索引select_by_visible_testx(“文本值”)下拉框的文本值
sel = edge.find_element_by_xpath("//select[@id='nr']") for selectIndex in range(len(sel.options)): # 索引 print(selectIndex) Select(sel).select_by_value('50') # 显示50条 图片处理 # 截图 edge.get_screenshot_as_file(r'截图后保存路径') # 获取网页图片二进制数据 edge.find_element_by_xpath(xx).screenshot_as_png() # 对页面进行截图,返回二进制数据 edge.get_screenshot_as_png() 其他属性 # 获取当前页面url driver.current_url # 获取当前html源码 driver.page_source # 获取当前页面标题 driver.title # 获取浏览器名称(chrome) driver.name # 对页面进行截图,返回二进制数据 driver.get_screenshot_as_png() # 设置浏览器尺寸 driver.get_window_size() # 获取浏览器尺寸,位置 driver.get_window_rect() # 获取浏览器位置(左上角) driver.get_window_position() # 设置浏览器尺寸 driver.set_window_size(width=1000, height=600) # 设置浏览器位置(左上角) driver.set_window_position(x=500, y=600) # 设置浏览器的尺寸,位置 driver.set_window_rect(x=200, y=400, width=1000, height=600) 无头浏览器 from selenium import webdriver from selenium.webdriver import ChromeOptions option = ChromeOptions() option.add_argument('--headless') # 都无头了要个锤子图片,不用gpu渲染 option.add_argument("--disable-gpu") browser = webdriver.Chrome(options=option) 反屏蔽

防止webdriver检测不通过,感谢 @CSDN博主「小小明-代码实体」

from selenium import webdriver from selenium.webdriver import ChromeOptions option = ChromeOptions() option.add_argument("--headless") option.add_experimental_option('excludeSwitches', ['enable-automation']) option.add_experimental_option('useAutomationExtension', False) option.add_argument('user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36') option.add_argument("--disable-blink-features=AutomationControlled") browser = webdriver.Chrome(options=option) # https://github.com/kingname/stealth.min.js with open('stealth.min.js') as f: js = f.read() browser.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', { 'source': js }) 总结

由于无论去哪都携带着十几个纸质笔记本过于不便,最近计划将笔记本内容全部搬到CSDN做存储。

本文结合了我的爬虫笔记和网络大佬(小小明-代码实体,Dream丶Killer)的博客,对爬虫学习做一个总结。


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #爬虫解析模块bs4 #selenium