如何使用Shell构建多进程的CommandlineFu爬虫(shell,编程语言)

时间:2024-04-28 16:21:20 作者 : 石家庄SEO 分类 : 编程语言
  • TAG :

    %E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8Shell%E6%9E%84%E5%BB%BA%E5%A4%9A%E8%BF%9B%E7%A8%8B%E7%9A%84CommandlineFu%E7%88%AC%E8%99%AB

CommandlineFu是一个记录脚本片段的网站,每个片段都有对应的功能说明和对应的标签。我想要做的就是尝试用 shell 写一个多进程的爬虫把这些代码片段记录在一个 org 文件中。

这个脚本需要能够通过-n参数指定并发的爬虫数(默认为 CPU 核的数量),还要能通过-f指定保存的 org 文件路径(默认输出到 stdout)。

我们需要一个进程从 CommandlineFu 的浏览列表中抽取各个脚本片段的 URL,这个进程将抽取出来的 URL 存放到一个队列中,再由各个爬虫进程从进程中读取 URL 并从中抽取出对应的代码片段、描述说明和标签信息写入 org 文件中。

这里就会遇到三个问题:

鸿蒙官方战略合作共建——HarmonyOS技术社区

进程之间通讯的队列如何实现

如何从页面中抽取出 URL、代码片段、描述说明、标签等信息

多进程对同一文件进行读写时的乱序问题

这个问题比较好解决,我们可以通过一个命名管道来实现:

从页面中提取元素内容主要有两种方法:

鸿蒙官方战略合作共建——HarmonyOS技术社区

对于简单的 HTML 页面,我们可以通过sedgrepawk等工具通过正则表达式匹配的方式来从 HTML 中抽取信息。

通过html-xml-utils工具集中的hxselect来根据 CSS 选择器提取相关元素。

这里我们使用html-xml-utils工具来提取:

这里需要注意的是:hxselect 对 HTML 解析时要求遵循严格的 XML 规范,因此在用 hxselect 解析之前需要先经过 hxclean 矫正。另外,为了防止 HTML 过大,超过参数列表长度,这里允许通过管道的形式将 HTML 内容传入。

这里要解决的是上面提到的第三个问题:多进程对管道进行读写时如何保障不出现乱序?为此,我们需要在写入文件时对文件加锁,然后在写完文件后对文件解锁,在 shell 中我们可以使用flock来对文件进行枷锁。 关于 flock 的使用方法和注意事项,请参见另一篇博文 Linux shell flock 文件锁的用法及注意事项。

由于需要在flock子进程中使用函数extract_views_from_browse_page,因此需要先导出该函数:

由于网络问题,使用 curl 获取内容可能失败,需要重复获取:

collector 用来从种子 URL 中抓取待爬的 URL,写入管道文件中,写操作期间管道文件同时作为锁文件:

这里要注意的是,在找不到下一页 URL 后,我们用一个 for 循环往队列里写入了 =proc_num= 个空行,这一步的目的是让后面解析代码片段的爬虫进程能够正常退出,而不至于被阻塞。

我们需要从脚本片段的页面中抽取标题、代码片段、描述说明以及标签信息,同时将这些内容按 org 模式的格式写入存储文件中。

这里抽取信息的方法跟上面的类似,不过代码片段和描述说明中可能有一些 HTML 代码,因此通过 pandoc 将之转换为 org 格式的内容。

注意***输出 org 模式的格式并写入存储文件中的代码不要写成下面这样:

它的意思是使用flockcat命令进行加锁,再把flock整个命令的结果通过重定向输出到存储文件中,而重定向输出的这个过程是没有加锁的。

spider 从管道文件中读取待抓取的 URL,然后实施真正的抓取动作。

这里要注意的是,为了防止发生死锁,从管道中读取 URL 时设置了超时,当出现超时就意味着生产进程赶不上消费进程的消费速度,因此消费进程休眠一秒后再次检查队列中的 URL。

通过重新定义extract_views_from_browse_pageextract_nextpage_from-browse_pageview_page_handler这几个函数, 以及提供一个新的种子 URL,我们可以很容易将其改造成抓取其他网站的多进程爬虫。

例如通过下面这段代码,就可以用来爬取xkcd上的漫画:

本文:如何使用Shell构建多进程的CommandlineFu爬虫的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:如何编写更好的CSS下一篇:

25 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18