前言

最近朋友在搞文案的时候提出了个需求,想要下载某站的小说,但是该网站的小说现在是不允许用户下载小说了,因此这个脚本出现了,用于扒取该网站的小说,并将扒取的内容成.txt格式的文件。

需求分析

这里我想的有两个解决方案

  • 通过网络请求工具获取网页内部的文章并写入文本,同时获取下一章的链接,然后调用新的请求,直至没有解析到下一章的按钮就结束写入
  • 模拟用户在浏览器操作,获取当前网页内容并写入文本,获取完毕后点击下一章继续获取,直至没有下一章按钮就结束写入

这里我们使用第二种方式来实现

技术框架

用到的库有如下几种:

  • Python: 3.7.7
  • selenium webdriver:4.4.3
    Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。
  • BeautifulSoup(bs4):4.11.1
    BeautifulSoup是一个可以从HTML或XML文件中提取数据的Python库。

开发准备

下载浏览器驱动

由于我们使用的selenium是模拟用户在浏览器操作,它需要通过webdriver驱动来调用本机的浏览器,所以我们需要下载与本机浏览器版本一致的驱动,这里以谷歌浏览器为示例,除此之外,selenium还支持其他浏览器的驱动,这里不进行深入了解

查看本机浏览器版本

image-1663809857751
点击帮助,关于 Google Chrome,弹出以下页面
image-1663809915887
在这里我们记录下自己的浏览器版本

下载浏览器驱动

完成上面的操作后,我们打开下面的链接,去下载谷歌浏览器驱动:http://chromedriver.storage.googleapis.com/index.html
这里我们选择与本机浏览器相近的版本
image-1663810138541
下载 chromedriver_win32.zip
image-1663825251408
下载完成查找python安装路径

C:\Users\liaoy>where python
C:\Users\liaoy\AppData\Local\Programs\Python\Python37\python.exe
C:\Users\liaoy\AppData\Local\Microsoft\WindowsApps\python.exe

这里我们进入到python根目录,并将chromedriver_win32.zip 解压后的chromedriver.exe复制到该目录。
image-1663825517934
至此,我们的环境就安装好了,接下来直接上代码

代码实现

import time

from selenium import webdriver
from bs4 import BeautifulSoup
from selenium.common import NoSuchElementException
from selenium.webdriver.common.by import By


def print_text(page_source, note):
    if page_source is not None:
        # 获取访问页面的内容
        soup = BeautifulSoup(page_source)
        # 遍历所有span标签
        for span in soup.findAll("span", class_="content-wrap"):
            note.write(span.get_text())


if __name__ == '__main__':
    options = webdriver.ChromeOptions()  # 实例化浏览器选项
    options.add_argument('--headless')  # 添加无头模式
    options.add_argument('ignore-certificate-errors')  # 解决“您的链接不是私密链接”错误
    driver = webdriver.Chrome(executable_path='chromedriver',
                              options=options)  # 启动chrome浏览器,executable_path指定的是驱动路径
    driver.get("https://read.qidian.com/chapter/hbIfVTSpixsEGYrhBm4H8w2/UtU3j7SgUdnM5j8_3RRvhw2/")  # 访问起点
    # 要保存的文本路径
    Note = open('C:\\Users\\liaoy\\Desktop\\' + driver.title.split('_', 1)[0] + '.txt', mode='w', encoding='utf-8')
    while True:
        # 模拟浏览器滚动
        for i in range(1, 5):
            driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')
        time.sleep(2)
        # 写入网页内容到文本
        print_text(driver.page_source, Note)
        # 关闭指南弹窗
        try:
            znBtn = driver.find_element(By.CSS_SELECTOR, "a.lbf-panel-close.lbf-icon.lbf-icon-close")
        except NoSuchElementException:
            znBtn = None
        if znBtn is not None:
            time.sleep(2)
            # 点击弹窗关闭按钮
            webdriver.ActionChains(driver).move_to_element(znBtn).click(znBtn).perform()
        # 切换至登录弹窗iframe
        driver.switch_to.frame(driver.find_element(By.ID, "loginIfr"))
        # 关闭登录弹窗
        try:
            closeBtn = driver.find_element(By.ID, "close")
        except NoSuchElementException:
            closeBtn = None
        if closeBtn is not None:
            time.sleep(2)
            # 点击弹窗关闭按钮
            webdriver.ActionChains(driver).move_to_element(closeBtn).click(closeBtn).perform()
        # 切回主页
        driver.switch_to.default_content()
        # 跳转至下一页
        try:
            btn = driver.find_element(By.ID, "j_chapterNext")
        except NoSuchElementException:
            btn = None
            # 结束文本输入
            Note.close()
            # 关闭浏览器
            driver.close()
        if btn is not None:
            # 点击下一页按钮
            webdriver.ActionChains(driver).move_to_element(btn).click(btn).perform()

上面的代码使用了很多try和except关键字, 由于我们在使用driver.find_element函数来获取页面元素的时候,如果找不到该元素则会报错,并且终止程序,由于弹窗比较多,有的页面有的时候有有的时候没有 这里无奈只能一个一个的捕获异常避免程序中断