从微信读书更改体验卡规则到发扬“互联网精神”

1,916 阅读3分钟

背景

我正在微信读书看一部小说,正看到兴起发现需要购买会员,之前都是体验卡看的,没想到腾讯改了规则了。早知道去年就看完了。 现在是“钱我不想付,书我又想看,怎么办?”。思考半天,做了一个违背腾讯想法的决定,我应该发挥下互联网精神。

从各大网站看了下,倒是可以正常看书,但是要么得下载他们的app,要么就只能看不能下载?堂堂一个程序员怎么能被这点困难给难住? 当然是把网站的书籍爬下来放到微信读书接着看了。

于是开始谋划怎么将自己想要的小说给导出本地然后再导入微信读书。首先想到的自然是puppeteer来模拟手动操作浏览器然后再将 找到的小说导出。

puppeteer介绍

Puppeteer 是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。Puppeteer 默认以 headless 模式运行,但是可以通过修改配置文件运行“有头”模式。

能做什么?

你可以在浏览器中手动执行的绝大多数操作都可以使用 Puppeteer 来完成! 下面是一些示例:

以上是官网的介绍,我们可以通过操作puppeteer来模拟手动搜索和点击文章,然后再将对应文本下载到本地。

使用方式

安装
npm i puppeteer
# or "yarn add puppeteer"

当你安装 Puppeteer 时,它会下载最新版本的Chromium(~170MB Mac,~282MB Linux,~280MB Win),以保证可以使用 API。

使用
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await page.screenshot({path: 'example.png'});

  await browser.close();
})();
puppeteer-core

puppeteer会默认下载对应的Chromium,但是一般我们开发都已经安装,没必要再次安装。所以使用这个包即可。这个包默认不会下载 Chromium。

实现

这里我以笔趣阁来作为示例。 先梳理下逻辑:

  1. 先去网站搜索书名,然后从索索列表按作者名字来找到想要的书籍;
  2. 然后点击书名进去小说,此时进去的书籍包含基本信息和章节目录。如图:

img_1.png 3. 要依次点击每章节内容,具体内容如图示: 

img_2.png 4. 将所有的文本拼接然后再导出即可。

代码实现

  1. 创建page实例;

    const browser = await puppeteer.launch({
        executablePath: 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe',
        ignoreHTTPSErrors: true, // 忽略https报错
    })
    const page = await browser.newPage()
    

    注意executablePath字段是你自己的chrome安装路径;

  2. 获取搜索结果并将数据做匹配;

    // 搜索结果
    const searchResult = await page.$$eval('#book-list li', books => books.map((book, i) => {
        if (i > 0) {
          const bookItem = Array.from(book.querySelectorAll('span'))
          if (bookItem[2].querySelector('a')) {
            return {
              name: bookItem[2].querySelector('a').title, // 书名
              author: bookItem[3].innerText, // 作者
              link: bookItem[2].querySelector('a').href, // 地址
            }
          }
        }
    }))
    const bookInfo = bookArr.find(book => book.author?.includes(author?.trim()))
    const bookLink = bookInfo?.link || bookArr[0].link
    
  3. 循环获取书籍章节,将文本拼接;

    // 目录列表
    const directoryItems = await page.$$eval('#list a', links => links.map(link => link.href))
    // 文本内容
    let fullText = `《${bookName}》` + '\n\n'
    for (let link of directoryItems) {
        await page.goto(link)
    
        const textTitle = await page.$eval('.bookname h1', el => el.innerText)
        const textContent = await page.$$eval('#htmlContent p', el => {
            let res = ''
            for (let element of el) {
                res += element.innerText
            }
            return res
        })
        console.log(`正在组织章节 -- ${textTitle} --`)
        fullText += textTitle + '\n' + textContent + '\n\n'
    }
    
  4. 下载;

    function downloadBook(content) {
        const filePath = path.join(__dirname, '..', '/static', `/${bookName}.txt`) // static下创建
    
        fs.writeFileSync(filePath, content)
    }
    

结果

img.png

再到微信读书PC端官网将文本导入 img_3.png

然后就可以在手机上继续看书了。代码已经上传到:github.com/Zuojiangtao…