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()的时间不够长,可以根据自身情况调整,或者可以多运行几次(如果有其他好的方法可以,希望大佬可以带带我^_^)

 

posted @ 2020-07-25 09:00  kongbursi  阅读(539)  评论(0编辑  收藏  举报