.mulu_list li 选择器下面就是我们想要的内容,比较简单,herf 是链接,text 是标题。

crawl_detail_selector

首先预想一下,需要一个什么样的文件,提供什么样的功能?于是期望输入一个小说的网址,根据内置的爬取规则获取章节信息,首先保存章节信息到文件里面,然后继续爬取章节里面的内容,存储的地址同样是一个函数输入,并且我们希望控制一下并发量。

首先把它做成命令行的版本,便于直接测试,然后在后续再进行改写。

  • phin 是一个 node 下,基于 net 封装的一个请求模块,非常的小。
  • cherrio 则是类似于 jquerydom 选取器。
  • iconv-lite 是纯 javascript 实现的一个字符编码解码器,主要用于解码 gbk,因为比较老的网站都是 gbk 编码的。
  • jsonfile 可以方便的读取 json 文件,保存数据的时候会用到它。
  • url-join 是拼接 url 的工具,有考虑到一些有 query 的情况,所以使用库拼接,而不是直接字符串拼接。
  • make-dir 用来确保文件地址存在和创建文件。
  • ora 则用于下载进度的显示

pipeP,第一个参数是 Promise,之后的参数都是 then 里面的回调,这样就再也不用看见 链了,然后将每一个环节进行分割,具体入下。

  1. // 拉取数据并且转码
  2. const getHTML = (url, charset) => {
  3. return p(url).then(res => decode(res.body, charset))
  4. }
  5. // 装载内容,获取 $ 函数
  6. const loadContent = source => {
  7. const $ = cheerio.load(source)
  8. return selector => {
  9. return $(selector)
  10. }
  11. }
  12. // 去掉 then 链接
  13. const pipeP = (...args) => {
  14. return args.reduce((acc, prev) => acc.then(prev))
  15. }
  16. const buildSelector = (url, charset) =>
  17. pipeP(
  18. getHTML(url, charset),
  19. loadContent
  1. const loadContent = cheerio.load

而对于 getHTML 也可以稍微优化一小下,到这个层次,我觉得就差不多了。

那么还有没有继续优化的空间了呢,是有的。

  1. const decodeHTML = charset => body => decode(body, charset)
  2. const getBody = ({ body }) => body
  3. // 拉取数据并且转码
  4. const getHTML = (url, charset) =>
  5. pipeP(
  6. p(url),
  7. getBody,
  8. )

更多函数式知识请