python+selenium+bs4爬取百度文库内文字 && selenium 元素可以定位到,但是无法点击问题 && pycharm多行缩进、左移
先说一下可能用到的一些python知识
一、python中使用的是unicode编码, 而日常文本使用各类编码如:gbk utf-8 等等所以使用python进行文字读写操作时候经常会出现各种错误, 一般都是操作时没有进行转码操作.而转码则需要decode(解码)和encode(编码)方法.
如:
str1.decode(‘gbk’), 表示将gbk编码的字符串‘str1’转换成unicode编码.
str2.encode(‘gbk’), 表示将unicode编码的字符串‘str2’转换gbk编码.
二、写入数据的时候报错程序直接停止,这就不得不重视“Python UnicodeEncodeError: 'gbk' codec can't encode character ”解决方法
将网络数据流写入文件时时,我们会遇到几个编码:
1: #encoding='XXX' 这里(也就是python文件第一行的内容)的编码是指该python脚本文件本身的编码,无关紧要。只要XXX和文件本身的编码相同就行了。 比如notepad++ "格式"菜单里面里可以设置各种编码,这时需要保证该菜单里设置的编码和encoding XXX相同就行了,不同的话会报错
2:网络数据流的编码 比如获取网页,那么网络数据流的编码就是网页的编码。需要使用decode解码成unicode编码。
3:目标文件的编码 要将网络数据流的编码写入到新文件,那么我么需要指定新文件的编码。在windows下面,新文件的默认编码是gbk,这样的话,python解释器会用gbk编码去解析我们的网络数据流txt,然而txt此时已经是decode过的unicode编码,这样的话就会导致解析不了,出现上述问题。 解决的办法就是,改变目标文件的编码:
f = open("out.html","w",encoding='utf-8')
三、pycharm缩进
1、pycharm使多行代码同时缩进、左移
鼠标选中多行代码后,按下Tab键,一次缩进四个字符
2、pycharm使多行代码同时左移
鼠标选中多行代码后,同时按住shift+Tab键,一次左移四个字符
四、time.sleep(t)
参数:t -- 推迟执行的秒数。
五、selenium 元素可以定位到,但是无法点击问题
描述:页面元素可以定位到,但是无法点击click。元素可能被一个透明div覆盖了
解决方案:
1.在执行click之前多休眠几秒
2.确认自己的元素是否定位正确,是否有id,name,class相同的元素,加下划线的是遮挡的div确定它的位置判断他的z_index是否大于你要点击元素的z_index
3.用Enter键代替click
4、将页面拖拽到要点击的元素位置,例如百度文库点击继续阅读展示全部内容(代码如下)
from selenium import webdriver from selenium.webdriver.common.keys import Keys driver = webdriver.Chrome('D:/chromedriver.exe') driver.get("https://wenku.baidu.com/view/aa31a84bcf84b9d528ea7a2c.html") page = driver.find_element_by_xpath("//*[@id='html-reader-go-more']/div[2]/div[1]/span/span[2]") driver.execute_script('arguments[0].scrollIntoView();', page) #拖动到可见的元素去 driver.find_element_by_xpath("//*[@id='html-reader-go-more']/div[2]/div[1]/p").click()
六、爬取百度文库连接:https://wenku.baidu.com/view/df34290a763231126edb11f9.html
原本我就没有想着要去用自动化工具去爬取,本来想着取用requests模拟请求,顶多就是麻烦一下弄弄js,但是我一看百度文库它的请求头
找这个文件找了半天,主要是它的文字不是连续的,我刚开始大致一看都没有找到。我还以为怎么了(翻车现场)。。。弄了半天可以确定0.png?这样类型的传递的是文库的照片,0.json传递的是文库的文字
但是这个请求头的url太长了,,突然就不想用requests模拟请求了
那就用selenium自动化工具+bs4解析页面,如果没有安装python的selenium库和selenium对应的浏览器驱动可以看一下:安装python的selenium库和驱动
接下来我们把思路和代码说一下
1、首先导入一下需要用到的模块
from selenium import webdriver from bs4 import BeautifulSoup from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time
2、因为这个页面是动态的,我们的selenium检测到浏览器框架之后就会返回源码,但是它不会去检测这个页面的动态加载部分是否加载出来,所以我们需要要求它去检测一下
这两个东西就是表示的是百度文库中文库是第几页,上图表示的是百度文库的第二页的div元素,第三页如下
这样我就可以确定,这个肯定可以作为检测条件
num = input('输入总页数:') st = "pageNo-" st_nums = st+str(num) #先构建一下最后一页的属性值
3、使用selenium模拟浏览器,并打开指定网址
browser = webdriver.Chrome("D:\python-senium\chromedriver.exe")#里面传的参数是你selenium驱动所在位置 browser.get('https://wenku.baidu.com/view/df34290a763231126edb11f9.html') #发送请求
4、我们使用selenium中的显示等待,初始化最长等待时间为10s。并等待我们要点击“继续阅读”出现,然后将浏览器页面移动到这里
wait = WebDriverWait(browser,10) time.sleep(5) wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#html-reader-go-more > div.continue-to-read > div.banner-more-btn > span')))#等待条件:找到文库中“继续阅读”字样,并等待其出现 page = browser.find_element_by_xpath("//*[@id='html-reader-go-more']/div[2]/div[1]/span") #找到页面中“继续阅读”所在位置 #js = "document.getElementsByClassName('banner-more-btn').style.visibility='hidden'" #browser.execute_script(js) #这个js代码是我原来以为是“继续阅读”被一个空的div包裹所以不能点击,然后我尝试把这个div掩盖掉,结果js代码运行失败。。。 browser.execute_script('arguments[0].scrollIntoView();', page) #拖动到可见的元素“继续阅读”去
5、等待“继续阅读”可以点击就点击它,然后等待文库中最后一页也加载出来就返回页面源码
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#html-reader-go-more > div.continue-to-read > div.banner-more-btn > span'))).click() wait.until(EC.presence_of_element_located((By.ID,st_nums))) #等待文库中最后一页也加载出来 html = browser.page_source
6、我们发现这些文字都被一个class属性值为“ie-fix”所包裹,那我们就把它所包裹的p标签都拿出来
its_p = soup.select(".ie-fix p")
然后对这个列表进行遍历,并输出其中的文本,并写入文件ab.txt中
soup = BeautifulSoup(html,"html.parser") #使用python内置解析html库 def get_context(): try: its_p = soup.select(".ie-fix p") for it_p in its_p: print(it_p.text,end='') with open('ab.txt','a',encoding='utf-8') as f: f.write(it_p.text) except: print('出错了') get_context() #调用函数 browser.close() #关闭浏览器
全部代码:
from selenium import webdriver from bs4 import BeautifulSoup from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time num = input('输入总页数:') st = "pageNo-" st_nums = st+str(num) '''''' browser = webdriver.Chrome("D:\python-senium\chromedriver.exe") browser.get('https://wenku.baidu.com/view/df34290a763231126edb11f9.html') wait = WebDriverWait(browser,10) time.sleep(5) wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#html-reader-go-more > div.continue-to-read > div.banner-more-btn > span'))) page = browser.find_element_by_xpath("//*[@id='html-reader-go-more']/div[2]/div[1]/span") #js = "document.getElementsByClassName('banner-more-btn').style.visibility='hidden'" #browser.execute_script(js) browser.execute_script('arguments[0].scrollIntoView();', page) #拖动到可见的元素去 wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#html-reader-go-more > div.continue-to-read > div.banner-more-btn > span'))).click() wait.until(EC.presence_of_element_located((By.ID,st_nums))) html = browser.page_source soup = BeautifulSoup(html,"html.parser") def get_context(): try: its_p = soup.select(".ie-fix p") for it_p in its_p: print(it_p.text,end='') with open('ab.txt','a',encoding='utf-8') as f: f.write(it_p.text) except: print('出错了') get_context() browser.close()
结果:
缺陷:
这个代码不会去爬取文库中图片信息,所以要是爬取ppt等文库还是不要用了(后面爬ppt的我会再写一篇博客)
提示:
也是后代码会运行出错,主要原因是time.sleep()的时间不够长,可以根据自身情况调整,或者可以多运行几次(如果有其他好的方法可以,希望大佬可以带带我^_^)