python爬虫

您所在的位置:网站首页 篮球南派打法 python爬虫

python爬虫

2023-03-22 21:08| 来源: 网络整理| 查看: 265

目录

一、背景​

1.1、selenium的发展

1.2、在爬虫中的应用

1.3selenium执行原理图

1.4、WebDriver,与WebElement

二、准备​

2.1、下载驱动

2.2、安装Selenium库

2.3、简单使用

三、实用操作​

3.1、查找节点

3.1.1、查找元素在网页中的位置

3.1.2、实现代码

3.2、获取节点属性,文本

3.3、节点交互

3.3.1、实现代码

3.3.2、实现效果​编辑

3.3.3、常用交互操作

3.4、显示等待

3.4.1、等待页面元素

3.4.2、实现代码

3.4.3、等待条件

3.5.1、获取cookies

2.5.2、携带cookies

3.5.3、实现效果​编辑

3.6、截屏

3.6.1、WebDriver对象实现截屏方法

3.6.2、WebElement对象实现截屏方法

3.6.3、实现代码

3.6.4、实现效果​编辑

3.7、反检测

3.7.1、适用场景

3.7.2、相关代码

3.8、设置无头

四、源码分析​

4.1、WebDriver的实例化源码探究

继承关系图

4.2、WebDrvierAPI原理探究

WebDrvierAPI在RemoteWebDrvier类的调用图

问题

解答

4.3、WebDriverWait的源码探究

问题

解答

总结

一、背景 1.1、selenium的发展

        Selenium最初是由Jason Huggins测试工程师为减少手工测试量做的基于JavaScript语言的代码库(这时是通过js注入的方式操作),之后不断的发展完善并合并了WebDrive项目,使之可以直接调用浏览器和操作系统内置的方法,解决了JavaScript环境的沙盒限制,发展成了现在我们经常使用的Selenium WebDriver。现在的selenium就像百度百科说的一样,Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。

1.2、在爬虫中的应用

      在爬取数据的时候,我们通常可以使用requests库,但是如果遇到加密的网站,就需要js逆向,相当复杂。但是我们还有一种方法,那就是使用自动化工具,实现可见即可爬,完成JavaScript动态渲染页面。

1.3selenium执行原理图

1.4、WebDriver,与WebElement

       WebDriver的核心是是一个浏览器驱动程序,他负责启动浏览器,并将控制权交个程序,同时还提供了API,直接使用并控制浏览器的内置对象,可以使用它来模拟用户的行为,如点击提交,填写文本框,键入网址等。

       WebElement表示 DOM 元素。 通常,所有与指定元素交互的操作都将通过此接口执行。如:如点击提交,填写文本框,键入网址,还包括获取文本属性等,这是不是很熟悉,原来WebElement属于WebDrvierAPI;它可以对指定网页元素进行操作。

       总结

WebElement属于WebDriver API,通常使用于对指定可见元素进行操作,一般的实现如下:通过WebDriverAPI提供的方法(如:find_element())进行元素定位并返回WebElement对象,再调用此对象对指定元素进行操作。

     

二、准备 2.1、下载驱动

查看浏览器版本,下载对应驱动,相关驱动的下载链接如下

Chrome驱动:chromedriver.storage.googleapis.com/index.html

Firefox驱动:Releases · mozilla/geckodriver (github.com)

Edge驱动:Microsoft Edge WebDriver - Microsoft Edge Developer

2.2、安装Selenium库 pip install selenium 2.3、简单使用 ​ from selenium import webdriver driver=webdriver.Chrome('./chromedriver.exe')#初始化WebDriver对象 driver.get('https://www.baidu.com')#访问百度 ​

Chrome的参数有很多,在这里我们初始化时传入的是executable_path,代表驱动的位置

驱动文件我放在了与代码同级目录下

三、实用操作 3.1、查找节点 3.1.1、查找元素在网页中的位置

3.1.2、实现代码 from selenium import webdriver from selenium.webdriver.common.by import By import time driver=webdriver.Chrome('./chromedriver.exe') driver.get('http://www.baidu.com') #css选择器进行筛选 #如果有多个元素被匹配,find_element只会获取第一个 result=driver.find_element(by=By.CSS_SELECTOR,value='.mnav.c-font-normal.c-color-t') print(result,'\n','---------------') #匹配多个 result_list=driver.find_elements(by=By.CSS_SELECTOR,value='.mnav.c-font-normal.c-color-t') for item in result_list: print(item) print('---------------') result_byid=driver.find_element(by=By.NAME,value='tj_more') print(result_byid) --------------- --------------- 3.2、获取节点属性,文本 driver=webdriver.Chrome('./chromedriver.exe') driver.get('http://www.baidu.com') result=driver.find_element(by=By.CSS_SELECTOR,value='.mnav.c-font-normal.c-color-t') print(result.text,result.get_attribute('href'),'\n','------------------------------------') result_list=driver.find_elements(by=By.CSS_SELECTOR,value='.mnav.c-font-normal.c-color-t') for item in result_list: print(item.text,item.get_attribute('href')) print('---------------------------------') #webdriver只与可见元素交互,如果该元素被隐藏,将不会被获取文本值,但是属性仍可获取到,可通过is_displayed()进行查看 result_byid=driver.find_element(by=By.NAME,value='tj_more') print({'text':result_byid.text,'href':result_byid.get_attribute('href')}) print(result_byid.is_displayed()) 新闻 http://news.baidu.com/ ------------------------------------ 新闻 http://news.baidu.com/ hao123 https://www.hao123.com/?src=from_pc 地图 http://map.baidu.com/ 贴吧 http://tieba.baidu.com/ 视频 https://haokan.baidu.com/?sfrom=baidu-top 图片 http://image.baidu.com/ 网盘 https://pan.baidu.com/?from=1026962h --------------------------------- {'text': '', 'href': 'http://www.baidu.com/more/'} False 3.3、节点交互 3.3.1、实现代码 from selenium import webdriver import time driver=webdriver.Chrome('./chromedriver.exe') driver.get('https://www.baidu.com') web_element=driver.find_element(By.CSS_SELECTOR,'.s_ipt') web_element.send_keys('张三') driver.find_element(By.CSS_SELECTOR,'[id="su"]').click() time.sleep(100) 3.3.2、实现效果 3.3.3、常用交互操作 操作含义click()点击按钮sendkeys()输入到单选框clear()清空输入框 3.4、显示等待 3.4.1、等待页面元素

3.4.2、实现代码 from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait driver=webdriver.Chrome('./chromedriver.exe') driver.get('http://www.baidu.com') wait=WebDriverWait(driver,10)#传入webdriver对象,设置等待时间 #等待节点,返回值是WebElement result_waitelement=wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'.mnav.c-font-normal.c-color-t'))) #等待节点并判断某个节点是否满足条件,返回值是bool类型 result_waittext=wait.until(EC.text_to_be_present_in_element((By.CLASS_NAME, 'mnav'), '新闻'))#等待节点包含的文本值 result_waitattribute=wait.until(EC.text_to_be_present_in_element_attribute((By.CLASS_NAME,'mnav'),'href','http://'))#等待节点的属性值 print(result_waitelement.text,result_waittext,result_waitattribute) 新闻 True True 3.4.3、等待条件 含义返回类型title_is判断title是否出现booltitle_contains判断title页面标题是否包含某些字符boolurl_contains判断当前url是否包含某个urlboolurl_matches判断当前url是否符合某种格式boolpresence_of_element_located判断某个元素是否被加载到了dom树里,但是并不代表这个元素可见 WebElement presence_of_all_elements_located判断至少有一个元素存在于dom树中,返回所有定位到的元素 List[WebElement] visibility_of_all_elements_located判断是否所有元素都在页面中可见boolvisibility_of_element_located某个节点可见booltext_to_be_present_in_element判断指定的节点文本值中是否包含了预期的字符串booltext_to_be_present_in_element_value判断指定的节点值中是否包含了预期的字符串booltext_to_be_present_in_element_attribute判断指定节点值中指定属性是否包含预期字符串boolalert_is_present是否出现警告提示框boolelement_to_be_clickable按bool 3.5、Cookie 3.5.1、获取cookies driver=webdriver.Chrome('./chromedriver.exe') driver.get('https://login.taobao.com/member/login.jhtml') time.sleep(40)#手动登录获取cookies cookies=driver.get_cookies() print(cookies,type(cookies)) with open('cookies.txt','w',encoding='utf-8') as f: json.dump(cookies,f) 2.5.2、携带cookies driver=webdriver.Chrome('chromedriver.exe') driver.get('https://www.taobao.com/') with open(r'./cookies.txt','r',encoding='utf-8') as f: cookie_data=json.load(f) for item in cookie_data: print(item) driver.add_cookie(item) driver.get('https://www.taobao.com/') time.sleep(30) 3.5.3、实现效果

3.6、截屏 3.6.1、WebDriver对象实现截屏方法 方法作用返回值get_screenshot_as_png()获取当前窗口的屏幕截图作为二进制数据。byteget_screenshot_as_file()将当前窗口的屏幕截图保存到 PNG 图像文件。boolget_screenshot_as_base64获取当前窗口的屏幕截图作为 base64 编码字符串String 3.6.2、WebElement对象实现截屏方法 方法作用返回值screenshot_as_png获取当前窗口的屏幕截图作为二进制数据。bytescreenshot()将当前窗口的屏幕截图保存到 PNG 图像文件。boolscreenshot_as_base64获取当前窗口的屏幕截图作为 base64 编码字符串String 3.6.3、实现代码 driver=webdriver.Chrome('./chromedriver.exe') driver.get('https://www.baidu.com') driver.get_screenshot_as_file('./screenshot_png/1.png')#默认存储位置在当前同级目录下 driver.find_element(By.ID,'lg').screenshot('./screenshot_png/2.png')#截取选定的节点图片 3.6.4、实现效果

3.7、反检测 3.7.1、适用场景

很多网站防止被恶意爬虫爬取,对selenium进行检测

3.7.2、相关代码 from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver import ChromeOptions from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC option=ChromeOptions() #设置无头模式 # option.add_argument('--headless') #反屏蔽处理 #以开发者模式启动调试chrome,可以去掉提示受到自动软件控制,隐藏提示条 option.add_experimental_option('excludeSwitches',['enable-automation']) option.add_experimental_option('useAutomationExtension',False)#去掉提示以开发者模式调用,自动拓展信息 driver = webdriver.Chrome('chromedriver.exe',options=option) # 将webdriver属性制为空 driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument',{ 'source':'Object.defineProperty(navigator,"webdriver",{get:()=>undefined})' }) 3.8、设置无头 from selenium import webdriver from selenium.webdriver import ChromeOptions #设置无头模式 option=ChromeOptions() option.add_argument('--headless') driver=webdriver.Chrome('chromedriver.exe',options=option) driver.get('https://www.baidu.com') driver.get_screenshot_as_png('baidu.png') 四、源码分析

4.1、WebDriver的实例化源码探究 from selenium import webdriver driver=webdriver.Chrome('./chromedriver.exe')

webdriver.Chrome()实例化WebDrvier的原理如下:

webdriver.py的部分源码

在这个文件中导入了WebDriver类并将WebDriver重命名,追溯WebDriver类可找到如下图的继承关系,WebDriver是继承了RemoteWebDriver类。

继承关系图

4.2、WebDrvierAPI原理探究

下图是webdriverAPI 在 RemoteWebDriver类的调用关系, RemoteWebDriver类的作用是向远程服务器发送命令。

WebDrvierAPI在RemoteWebDrvier类的调用图

 该类初始化了服务器连接对象,并发送执行的标准命令,如源码所示标准命令

问题

在selenium的原理执行图中我们可以知道,其实selenium底层是通过http协议来实现的,但是这些字符串是怎么转化成http请求的呢?

解答

RemoteWebDriver类是调用了RemoteConnect类实现发送http请求的

如下图在RemoteConnect类中的调用关系,在_commands字典中定义了每个命令对应的http请求,而且还是restful风格的,关于restful风格可以参考这篇文章Restful风格及实践_杜小白也想的美的博客-CSDN博客

 

4.3、WebDriverWait的源码探究 from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait driver=webdriver.Chrome('./chromedriver.exe') driver.get('http://www.baidu.com') wait=WebDriverWait(driver,10)#传入webdriver对象,设置等待时间 #等待节点,返回值是WebElement result_waitelement=wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'.mnav.c-font-normal.c-color-t')))

在上面的一段代码中,实现了对cass属性值为mnav c-font-normal c-color-t元素的等待,如果此节点出现在doc元素树中,将此节点返回封装成WebElement对象返回,那这些是如何实现的呢?

查看WebDriver部分源码

def __init__( self, driver, timeout: float, poll_frequency: float = POLL_FREQUENCY, ignored_exceptions: typing.Optional[WaitExcTypes] = None, ): :Args: - driver - Instance of WebDriver (Ie, Firefox, Chrome or Remote) - timeout - Number of seconds before timing out - poll_frequency - sleep interval between calls By default, it is 0.5 second. - ignored_exceptions - iterable structure of exception classes ignored during self._driver = driver self._timeout = float(timeout) def until(self, method, message: str = ""): """Calls the method provided with the driver as an argument until the \ return value does not evaluate to ``False``. :param method: callable(WebDriver) :param message: optional message for :exc:`TimeoutException` :returns: the result of the last call to `method` :raises: :exc:`selenium.common.exceptions.TimeoutException` if timeout occurs """ screen = None stacktrace = None end_time = time.monotonic() + self._timeout while True: try: value = method(self._driver) if value: return value except self._ignored_exceptions as exc: screen = getattr(exc, "screen", None) stacktrace = getattr(exc, "stacktrace", None) time.sleep(self._poll) if time.monotonic() > end_time: break raise TimeoutException(message, screen, stacktrace)

在until方法中的method(self._driver)实际上使用了闭包将

EC.presence_of_element_located((By.CSS_SELECTOR,'.mnav.c-font-normal.c-color-t'))作为内部方法返回,而且还调用了driver对象。

问题

那么什么是EC.presence_of_element_located((By.CSS_SELECTOR,'.mnav.c-font-normal.c-color-t'))呢?调用的这个driver对象是干嘛的呢?

解答

源码如下:

def presence_of_element_located(locator): """An expectation for checking that an element is present on the DOM of a page. This does not necessarily mean that the element is visible. locator - used to find the element returns the WebElement once it is located """ def _predicate(driver): return driver.find_element(*locator) return _predicate

这个方法调用了driver.find_element()

我们在看下其他等待方法,如:text_to_be_present_in_element

源码如下

def text_to_be_present_in_element(locator, text_): """An expectation for checking if the given text is present in the specified element. locator, text """ def _predicate(driver): try: element_text = driver.find_element(*locator).text return text_ in element_text except StaleElementReferenceException: return False return _predicate

它也是调用的drvier.find_element方法,但返回的是bool类型

总结

WaitDriver类实际上调用的是find_element等 WebDriverAPI方法并加入时间等待,一旦在设置的时间内没有找到这个指定元素并抛出超时错误。

 

​感谢你阅读到最后~ 

​期待你的关注、收藏、评论、点赞~

​愿我们一起变强

 

本文仅用于学习交流!!!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3