python爬虫系列第四次笔记之动态渲染页面爬取 您所在的位置:网站首页 python渲染html页面 python爬虫系列第四次笔记之动态渲染页面爬取

python爬虫系列第四次笔记之动态渲染页面爬取

2023-07-22 20:27| 来源: 网络整理| 查看: 265

为了解决异步渲染网页,我们直接模拟浏览器运行的方式来实现,这样就可以左到在浏览器中看到什么样,抓取的源码就是什么样,也就是可见即可爬。这样我们就可以不用管网页内部的javascript用了什么算法渲染页面,也就是所谓的js加密,也不用管网页后台的Ajax接口有哪些参数。

1Selenium的使用

在使用selenium之前,需要安装Driver文件,有ChromeDriver(适用chrome),GeckoDriver(适用firefox),PhantomJS。如何下载到csdn上直接搜索就有,需要注意的是除了PhantomJS以外,另外两个需要和你本机安装的浏览器版本相近(不要求完全一样,但是必须是相近的版本),这是必须要注意的。下载完成后,把exe文件复制粘贴到你安装的python文件中bin文件(或者DOC)同级目录下。

1.1selenium的基本用法 from selenium import webdriver import time driver = webdriver.Chrome() start_url = "https://www.baidu.com" driver.get(start_url) time.sleep(5) driver.close() driver.quit()

如果运行上面的代码之后,会弹出一个chrome浏览器页面,然后过5秒后退出 ,就说明你的运行文件版本以及安装位置是正确的,当然,这里可以换成Firefox(). 那么我们还可以做一些什么事呢?

#coding=utf-8 from selenium import webdriver import time driver = webdriver.Chrome() start_url = "https://www.baidu.com" driver.get(start_url) driver.find_element_by_id("kw").send_keys("长城") driver.find_element_by_id("su").click() time.sleep(5) driver.quit()

我们这里根据id定位元素,定位一个位置并给予它一个参数,然后下面使用click()方法实行点击一个按钮。实际上这里是给我们的百度输入框中输入长城这个值,然后点击“百度”按钮。最后过5秒钟,关闭页面。 那么继续

from selenium import webdriver import time driver = webdriver.Chrome() start_url = "https://www.baidu.com" driver.get(start_url) driver.find_element_by_id("kw").send_keys("长城") driver.find_element_by_id("su").click() time.sleep(5) print(driver.page_source.encode('GBK','ignore').decode('GBK')) driver.quit()

这里使用了编码解码的操作,为什么要这么做,是因为网页本身是utf-8,但我们爬取网页时用的是Unicode,但使用print()打印时,里面的内容应该是GBK编码,那么就需要我们将需要打印的数据后加上 .encode(‘GBK’,‘ignore’).decode(‘GBk’)第一个GBK是忽略掉非法字符,然后再译码。不然会报编码错误。这里会打印出网页的源码。 小结:

selenium的导包:from selenium import webdriverselenium创建driver对象:webdriver.PhantomJS()selenium请求数据:driver.get("http://www.baidu.com/")selenium查看数据: driver.page_source关闭无界面浏览器: driver.quit()根据id定位元素: driver.find_element_by_id(“kw”)操作点击事件: click()给输入框赋值:send_keys() 1.2selenium元素定位的方法 1.2.1定位方法 find_element_by_id (返回一个元素) 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_element和find_elements的区别 by_link_text和by_partial_link_tex的区别:全部文本和包含某个文本 这些解析方法在之前都有介绍,这里就不一一赘述,我们用一个例子来介绍这些方法。

from selenium import webdriver driver = webdriver.Chrome() driver.get("https://www.douban.com/") ret1 = driver.find_element_by_id("anony-nav") print(ret1) # 输出为: ret2 = driver.find_elements_by_id("anony-nav") print(ret2) #输出为:[] ret3 = driver.find_elements_by_xpath("//*[@id='anony-nav']/h1/a") print(len(ret3)) #输出为:1 ret4 = driver.find_elements_by_tag_name("h1") print(len(ret4)) #输出为:1 ret5 = driver.find_elements_by_link_text("下载豆瓣 App") print(len(ret5)) #输出为:1 ret6 = driver.find_elements_by_partial_link_text("豆瓣") print(len(ret6)) #输出为:20 driver.close()

这里调用的方法并不复杂,只是需要去网页中找到你想要的元素的id,或者class,或者xpath方法,需要注意的是xpath路径是可以直接在网页中右键点击elements中的元素,copy–》xpath,来获得。 还有css元素定位

from selenium import webdriver driver = webdriver.Chrome() driver.get('https://www.baidu.com') driver.find_element_by_class_name('s_ipt').send_keys('3浪还有') # driver.find_element_by_css_selector('#su').click() driver.find_element_by_class_name('btn self-btn bg s_btn').click() #其他css方法 # 通过id属性(css属性) driver.find_element_by_css_selector("#kw").send_keys("python") # 通过class属性定位(css属性) driver.find_element_by_css_selector(".s_ipt").send_keys("python") # 通过标签定位(css属性) driver.find_element_by_css_selector("input").send_keys("python") # 通过name属性定位(其他属性) driver.find_element_by_css_selector("[name='wd']").send_keys("python") # 通过autocomplete属性定位(其他属性) driver.find_element_by_css_selector("[autocomplete='off']").send_keys("python") # 通过type属性定位(其他属性) driver.find_element_by_css_selector("[type='text']").send_keys("python") # css也可以通过标签与属性的组合来定位元素 driver.find_element_by_css_selector("input.s_ipt").send_keys("python") driver.find_element_by_css_selector("input#kw").send_keys("python") driver.find_element_by_css_selector("input[id='kw']").send_keys("python") # css层级关系 driver.find_element_by_css_selector("form#form>span>input").send_keys("python") driver.find_element_by_css_selector("form.fm>span>inout").send_keys("python") # css逻辑运算 driver.find_element_by_css_selector("input[id='kw'][name='wd']").send_keys("python")

那么我们获得,或者说定位到了元素后我们需要怎么办呢?

1.2.2解析手段

在第一章介绍了赋予参数方法,和点击方法。那么还有什么方法? find_element仅仅能够获取元素,不能够直接获取其中的数据,如果需要获取数据需要使用以下方法:

获取文本:element.text获取属性值:element.get_attribute("href") 示例: #coding=gbk from selenium import webdriver driver =webdriver.Chrome() driver.get("https://www.douban.com/") ret4 = driver.find_elements_by_tag_name("h1") print(ret4[0].text) #输出:豆瓣 ret5 = driver.find_elements_by_link_text("下载豆瓣 App") print(ret5[0].get_attribute("href")) #输出:https://www.douban.com/doubanapp/app?channel=nimingye driver.close()

这里给出了返回txt内容和href,是不是和上一章的解析方法有些类似。 小结

根据xpath定位元素:driver.find_elements_by_xpath("//*[@id='s']/h1/a")根据class定位元素:driver.find_elements_by_class_name("box")根据link_text定位元素:driver.find_elements_by_link_text("下载豆瓣 App")根据tag_name定位元素:driver.find_elements_by_tag_name("h1")获取文本内容:element.text获取标签属性: element.get_attribute("href") 1.2.3其他方法

selenium 处理cookie

通过driver.get_cookies()能够获取所有的cookie

# 把cookie转化为字典 {cookie[‘name’]: cookie[‘value’] for cookie in driver.get_cookies()} #删除一条cookie driver.delete_cookie("CookieName") # 删除所有的cookie driver.delete_all_cookies()

页面等待

为什么需要等待

如果网站采用了动态html技术,那么页面上的部分元素出现时间便不能确定,这个时候就可以设置一个等待时间,强制要求在时间内出现,否则报错

页面等待的方法 time.sleep(10)

switch方法切换的操作

一个浏览器肯定会有很多窗口,所以我们肯定要有方法来实现窗口的切换。切换窗口的方法如下:

也可以使用 window_handles 方法来获取每个窗口的操作对象。例如: # 1. 获取当前所有的窗口 current_windows = driver.window_handles # 2. 根据窗口索引进行切换 driver.switch_to.window(current_windows[1])

iframe是html中常用的一种技术,即一个页面中嵌套了另一个网页,selenium默认是访问不了frame中的内容的,对应的解决思路是

driver.switch_to.frame()

在使用selenium登录qq邮箱的过程中,我们会发现,无法在邮箱的登录input标签中输入内容,通过观察源码可以发现,form表单在一个frame中,所以需要切换到frame中。这个方法使用的很多。

当你触发了某个事件之后,页面出现了弹窗提示,处理这个提示或者获取提示信息方法如下:

alert = driver.switch_to_alert()

页面前进和后退

driver.forward() #前进 driver.back() # 后退

selenium的优缺点

selenium能够执行页面上的js,对于js渲染的数据和模拟登陆处理起来非常容易selenium由于在获取页面的过程中会发送很多请求,所以效率非常低,所以在很多时候需要酌情使用

小结

获取cookie: get_cookies()删除cookie: delete_all_cookies()切换窗口:switch_to.window()切换iframe: switch_to.frame() 1.4实例说明

在给出例子之前,我们要想到,动态解析页面的时候,我们需要获取在网页上所有的内容,就必须要渲染出网页全部的页面,不然我们可能就会定位不到我们想要的信息,所以我们就需要进行页面的滚动,一直到页面最底部。 方法为:

from selenium import webdriver import time, random # 1.创建driver对象 driver = webdriver.Chrome() # 访问url地址 driver.get('https://www.csdn.net') for i in range(1, 10): # 构造滑动函数,scrollTo滚动,参数为滑动的距离 js = 'scrollTo(0, {})'.format(1000 * i) # execute_script 执行滑动轨迹 driver.execute_script(js) time.sleep(random.randint(1, 3)) print(driver.page_source)

这样运行后,页面就会滑到最底部,无需记忆,直接复制粘贴就行。 我们来一个比较狠的,我们来做一个斗鱼的弹幕机。

from selenium import webdriver from lxml import etree import time import re class DySpider(object): def __init__(self): self.driver = webdriver.Chrome() # 最大化窗口 self.driver.maximize_window() self.start_url = 'https://www.douyu.com/directory/all' self.driver.get('https://passport.douyu.com/member/login?') time.sleep(10) def parse_url(self): """ 关闭弹窗,执行滑动 :return:html_element(elements内容), num(最大页码数) """ self.driver.get(self.start_url) try: """访问后,没有弹窗,在此使用try嵌套""" time.sleep(3) self.driver.find_element_by_class_name('ZoomTip-tipHide').click() except: """没有弹窗,则pass""" pass """获取elements内容""" time.sleep(2) self.page_url() html_element = self.driver.page_source print(html_element) """提取翻页的最大页码数""" num = re.findall('dy-Pagination-item dy-Pagination-item-(\d+)',html_element)[5] """验证是否正常(成功)获取""" print('返回的页面共有:' + num) return num def page_url(self, num=None): """ 构造向下滑动 :return: """ if num is None: num = 10000 """每次向下滑动距离10000""" js = 'scrollTo(0, {})'.format(num) """执行滑动""" self.driver.execute_script(js) """滑动之后沉睡等待2秒""" time.sleep(2) def parse_page_url(self, num): """ 执行翻页 :param num: 页码数 """ """根据最大页码数的遍历,来执行点击下一页的次数""" for i in range(int(num) - 2): """调用滑动函数""" self.page_url() time.sleep(2) """下一页的点击事件""" self.driver.find_element_by_css_selector('#listAll > section.layout-Module.js-ListContent > div.layout-Module-container.layout-Cover.ListContent > div > ul > li.dy-Pagination-next > span').click() """每次成功下一页之后,获取其elements内容""" html_data = self.driver.page_source html_element = etree.HTML(html_data) self.save_id_data(html_element) def save_id_data(self, html_element): """ :param html_element: etree转换之后的对象 """ # 获取直播间的id列表 # html_element = etree.HTML(html_element) id_num = html_element.xpath('//*[@id="listAll"]/section[2]/div[2]/ul/li/div/a[1]/@href') # 直播间id去重 # id_num = list(set(id_num)) print(id_num) # 访问第一个直播间,达到去除窗口的效果 js = 'window.open("{}");'.format('https://www.douyu.com' + id_num[0]) self.driver.execute_script(js) time.sleep(2) # 获取所有浏览器窗口 windows = self.driver.window_handles # 窗口切换,切换到新打开的直播间窗口 self.driver.switch_to.window(windows[1]) # 关闭打开的窗口 self.driver.close() # 切换到初始窗口 self.driver.switch_to.window(windows[0]) for id in id_num: # 直播间的url地址拼接 url = 'https://www.douyu.com' + id # 调用函数 self.requests_url_by(url) # print(url) def requests_url_by(self, url): """ 访问直播 :param url: 直播间的url地址 """ # js代码执行打开url--直播间的url地址 js = 'window.open("{}");'.format(url) self.driver.execute_script(js) # 隐式等待 self.driver.implicitly_wait(10) # 获取当前所有窗口,返回一个列表 windows = self.driver.window_handles # 窗口切换,下标操作 self.driver.switch_to.window(windows[1]) try: for i in range(1, 3): text = '1' self.driver.find_element_by_css_selector('.ChatSend-txt').send_keys(text) # 输入弹幕 self.driver.find_element_by_css_selector('.ChatSend-button ').click() # 点击发送弹幕 print(f'弹幕----------已发送----------第{i}次') time.sleep(1.5) # 每一秒发送一次共发送20次 except: print('发送失败') self.driver.close() self.driver.switch_to.window(windows[0]) def run(self): num = self.parse_url() # self.save_id_data(html_element) self.parse_page_url(num) if __name__ == '__main__': dy = DySpider() dy.run()

这个案例会遍历现在斗鱼开播的直播间,然后在每个直播间发两遍‘1’,但是你需要首先在弹出来斗鱼登陆界面,扫码登陆你的斗鱼账号,不然你是不能发弹幕。该案例中用了很多方法,融汇贯通会很适合。我将在下一期讲解类方法的使用。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有