搜索引擎的预料库 —— 万恶的爬虫

利用MATLAB 4f光学系统,在Python中进行弗劳恩霍夫衍射和傅里叶面滤波——用镜头模拟光学图像处理。.zip 1.版本:matlab2014a/2019b/2024b 2.附赠案例数据可直接运行。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 立即下载

640?wx_fmt=png

本节我们来生产一个简单的语料库 —— 从果壳网爬点文章。后面我们将使用这些文章来完成索引构建和关键词查询功能。

https://www.guokr.com/article/438188

果壳网的文章很容易遍历,因为它的文章 id 是自增的。我查阅了站点的最新文章,发现这个 id 还没有超过 45w,所以我打算从 1 开始遍历,扫描出所有的有效文章。

但是扫描 45w 个 URL 会非常漫长,所以我开启了多线程。但是线程也不敢开太多,网站可能有反扒策略快速封禁 IP(我可不想去整 IP 代理池),也可能服务器计算能力有限,爬一爬网站就挂了。

我并不期望自己能扫描出所有的文章,有那么几百篇也就够了,做人也不宜太贪婪。

有同学建议我使用 Go 语言来爬,开启协程比线程方便多了。这个还是留给读者当作学习 Go 语言的练习题吧,我是打算一杆子 Java 写到底了 —— 因为玩 Lucene 是离不开 Java 的。

45w 个文章 ID 如何在多个线程之间分配,需要将所有的 id 塞进一个队列,然后让所有的线程来争抢么?这也是一个办法,不过我选择了使用 AtomicInteger 在多个线程之间共享。

爬到的文章内容放在哪里呢?只放在内存里会丢失,存储到磁盘上有需要序列化和反序列化也梃繁琐,还需要考虑文件内容如何存储。所以我打算把内容统统放到 Redis 中,这会非常方便。但是会不会放不下呢?我们来计算一下,一篇文章的内容量大概会占用 5k,如果有 45w 篇文章,那么就需要 45w * 5k 的内存,大概也只有 2个多G,我的苹果本内存 16G,存这点内容还是绰绰有余的。

爬到的文章是 HTML 格式的,每个网页除了文章内容本身之外,还有很多其它的外链以及广告。那如何将其中的核心文章内容抽取出来,这又是一个问题。我这里选择了 Java 的 HTML 解析库 JSoup,它使用起来有点类似于 JQuery,可以使用选择器来快速定位节点抽取内容。同时它还可以作为一个非常方便的抓取器,自带了 HTTP 的请求工具类。也许读者会以为我会使用高级的机器学习来自动抽取文章内容,很抱歉,实现成本有点高。

下面我们来看看如何使用 JSoup,先导入依赖

<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.12.1</version>
</dependency>

抓取文章,将自己浏览器的 UserAgent 拷贝过来作为机器人的 UserAgent,伪装成一个正常的浏览器。当文章不存在时,果壳网并不是返回标准的 404 错误码。我们需要通过抽取网页内容来判断,如果抽取到的文章标题或者内容是空的,那么我们就认为这篇文章无效不存在。

抽取内容成功后,将内容存储到 Redis 中。因为抽取 45w 个网页时间上会有点漫长,我担心程序可能跑到一半就崩溃了,然后又不得不重新开始遍历。所以我打算记录一下抽取的状态,将抽取成功的文章 id 记录到一个 Redis 集合中。同时因为这 45w 个整数 id 有效的文章有可能连一半都占不到,所以我还会将无效的文章 id 也给记录下来,减少因为程序重启带来的无效爬虫抓取动作。

var agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36";
var url = String.format("https://www.guokr.com/article/%d/", id);
var res = Jsoup.connect(url)
        .header("HOST", "www.guokr.com")
        .header("User-Agent", agent)
        .execute();
if(res.statusCode() == 200) {
    var doc = Jsoup.parse(res.body());
    // 像极了 JQuery 有木有
    var divTitle = "div[class~=layout__Skeleton.*__ArticleTitle.*]";
    var divHTML = "div[class~=layout__Skeleton.*__ArticleContent.*]";
    var title = doc.selectFirst(divTitle).html();
    var html = doc.selectFirst(divHTML).html();
    if(!title.isEmpty() && !html.isEmpty()) {
      save2Redis(id, title, html);
      return;
    }
}
saveFailedId2Redis(id);

将文章内容存储到 Redis 中我打算使用 Hash 结构,分别存储 title 和 html 内容。因为后续我们还需要对文本进行去标签化等操作,这时就可以继续使用 Hash 结构存储处理后的干净的文本内容。

var redis = new JedisPool();
var db = redis.getResource();
// 将有效的文章 id 存储到一个集合中
db.sadd("valid_article_ids", String.valueOf(id));
db.hset(String.format("article_%d", id), "title", title);
db.hset(String.format("article_%d", id), "html", html);
db.close();

代码中的 db.Close() 表示将当前的 Jedis 链接归还给连接池,而不是关闭链接。

无效的文章 id 我们也要存起来。

db = redis.getResource();
db.sadd("invalid_article_ids", String.valueOf(id));
db.close();

这样当每个线程抢到一个 ID 之后,它要做的第一件事就是判断这个 ID 是否在有效的和无效的文章 ID 列表中,如果已经存在了,那就直接去抢下一个文章 ID。

var db = redis.getResource();
if(db.sismember("valid_article_ids", String.valueOf(id))) {
    db.close();
    return;
}
if(db.sismember("invalid_article_ids", String.valueOf(id))) {
    db.close();
    return;
}
db.close();
// 去爬吧
fetchArticle(id);

下面我们再来看看并发线程是如何开启和结束的,我只用了 16 个线程。最后需要使用 thread.join() 来等待所有线程终止,如果没有这行代码,程序会立即退出,想想为什么?

var idGen = new AtomicInteger();
var threads = new Thread[16];
var redis = new JedisPool();
for(int i=0;i<threads.length;i++) {
    threads[i] = new Thread(() -> {
        while(true) {
            var id = idGen.incrementAndGet();
            if(id > 450000) {
                break;
            }
            crawlArticle(redis, id);
        }
    });
    threads[i].start();
}
for(var thread: threads) {
    thread.join();
}
System.out.println("Game Over!");

程序总算跑起来了,但是跑了一段时间后我去 Redis 中查看了一下有效文章 ID 集合,发现里面之后 200 多个有效的文章 ID。果壳网难道只有 200 多篇文章,不可能,果壳网里面的科学文章可是包罗万象,少说应该也有几万篇吧,那这个究竟是怎么回事呢?

于是我将 Redis 中无效的文章 ID 集合清空,又重新跑了一下程序,打印了 HTTP 请求的状态码,发现非常非常多的 503 Service Unavailable 响应。我明白了 —— 网站的反爬策略起作用了,或者是服务扛不住 —— 挂了。我倾向于后者,因为我发现 HTTP 响应时好时坏,服务处于不稳定状态。通常反爬策略会持续一段时间封禁 IP,不会让你一会难受一会爽。

很无奈,我多跑了几次程序,最终收集了不到 1000 篇文章。这作为搜索引擎的语料库也差不多够用了,再死磕下去似乎会很不划算,所以今天的爬虫就到此为止。下一篇文章我们来使用 Lucene 构建文章的索引。

如果你想要仔细阅读今天的爬虫代码,可以点击「阅读原文」进入 Github Gist 查看(有可能需要翻墙)。如果你要尝试本节代码,请将线程数调低一点,以免对果壳网产生 DDOS 攻击 —— 后果自负。

下面是有钱(有老钱)的字节跳动内推入口,找出自己心意的职位后,请勇于投递你的个人简历,内部系统的数据安全性做得非常到位,我是看不到你们的简历内容的,所以不必太担心个人隐私问题。北京、上海、深圳、杭州、成都、广州等城市的职位都有,Python、Java、Golang、算法、数据、分布式计算和存储的岗位也都有,各人发挥自己的搜商自行搜寻。请认真投递自己的简历,否则可能连面试的机会都没有。

640?wx_fmt=png

工业互联网工控安全与工业质检AI大模型建设方案.pptx 立即下载

相关推荐

通信行业CentOS 7内核网络栈优化:高并发连接下UDP/TCP性能调优与系统资源管理

内容概要:本文聚焦于CentOS 7系统在通信行业高并发场景下的性能调优实践,重点围绕内核网络栈优化展开,涵盖UDP/TCP缓冲区调整、文件句柄与连接跟踪表扩容、TIME_WAIT状态复用、软中断分布优化及tuned工具的自动化调优。通过具体配置参数和实际案例(如VoIP软交换系统)深入解析各项调优措施的设计原理与实施效果,有效解决高CPS下丢包、连接失败等问题,并展望了向云化、eBPF等动态智能调优方向的发展趋势。; 适合人群:从事通信系统运维、网络开发或Linux系统性能优化的技术人员,具备一定操作系统和网络基础知识,工作经验1年以上的中初级工程师。; 使用场景及目标:①应用于软交换、媒体网关、信令网关等高并发通信设备的系统调优;②解决UDP丢包、conntrack表满、TCP连接队列溢出等典型性能瓶颈;③提升系统在小包高频、低时延要求场景下的稳定性和吞吐能力。; 阅读建议:建议结合实际生产环境或测试平台同步验证文中配置,重点关注参数背后的物理意义(如BDP、softirq、conntrack机制),并配合ss、conntrack、dmesg等命令进行调优前后对比分析,确保安全可控地实施变更。

统计自然语言处理(第二版)学习笔记:第四章 语料库与语言知识库

目录: 1.基本概念 2.预料库的技术发展 3.国内语料库研究状况 4.语料库的类型 5.典型语料库介绍 1.基本概念 语料库(corpus):存放语言材料的仓库(语言数据库)。 语料库语言学(corpus linguistics):基于语料库进行语言学研究。 研究内容: 语料库的建设与编纂; 语料库的加工和管理技术; 语料库的使用,包括在语言学研究(言语、 词汇和语义研究等)中的应用和在自然...

XB_please的博客 2738

2024 《计算机网络》实验教学指导书.doc

2024 《计算机网络》实验教学指导书.doc

雅思资料汇总

雅思考满分 :听力和单词是预料库的单词雅思小站:电子版真题,解析雅思哥:练习口语、查看口语题库听力分为 4 个 Section,每个 Section 10 题,难度一般递进。两种题型:填空:基础(单句,问答),表格,图(示意图,流程图,地图)选择配对:多选、单选、配对琐碎生活类对话。例如租房,开账户,报名,看病等,主要目的都是为了让你填写资料,数字,人名地名等。主要就是拼写单词,难度不高,争取全对。文化生活类独白。

银晗的学习博客 4872

不平衡电网下自抗扰顺序模型预测PWM整流器控制仿真模型(Simulink仿真实现)

内容概要:本文围绕面向城市空中交通的多无人机路径规划问题展开研究,提出了一套融合全局规划、动态避障与局部协同调整的综合路径规划方法。研究内容涵盖基于改进RRT算法与图论的全局路径规划、基于动态风险场和动态窗口法(DWA)的模型预测控制实现动态避障,以及基于分布式协同控制的多无人机局部路径协同策略。通过Matlab平台构建仿真环境,在多种典型城市交通场景下对所提方法进行了系统性验证,结果表明该方法在路径安全性、编队稳定性与任务效率方面表现优异。文章还深入探讨了算法的创新点与未来研究方向,为复杂城市环境下多无人机系统的自主协同提供了理论支撑与技术路径。; 适合人群:具备自动化、控制理论、计算机科学或相关领域基础知识,从事无人机系统、智能交通、路径规划、多智能体协同控制等方向研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①为城市空中交通系统中的多无人机安全、高效飞行提供可靠的路径规划解决方案;②支持在复杂、动态的城市场景中开展无人机自主导航、编队飞行与协同控制的技术研究与仿真验证。; 阅读建议:建议结合提供的Matlab代码进行实践操作,重点关注算法的具体实现细节、参数配置对性能的影响以及不同仿真场景下的实验设计,以深入理解各模块的集成逻辑与实际应用效果。

DEMATEL-ISM模型的Python实现——方法介绍以及代码复现

本文参考文献与网络资料,对DEMATEL-ISM方法做了介绍何步骤描述,并给出Python代码进行了计算和绘图。

cros1的博客 2万+

【上中课程】词云Word Cloud(标签云、词频分析、文本分析)的实现——应用jieba库和wordcloud库

词云,又称文字云、标签云,是对文本数据中出现频率较高的“关键词”在视觉上的突出呈现,形成关键词的渲染形成类似云一样的彩色图片,从而一眼就可以领略文本数据的主要表达意思。常见于博客、微博、文章分析等。 基本概念: 1.语 料 库:预料库是我们要分析的所有文档的集合 2.中文分词:指的是将一个汉字序列切成一个一个单独的词 3.停 用 词:数据处理的时候,自动过滤掉某些字或词...

安徐正静 2927

Cadence数模混合仿真实战:从Verilog到ADE L的完整流程解析

本文详细解析了Cadence数模混合仿真的完整流程,从Verilog代码编写到ADE L仿真环境配置。通过实战案例讲解如何创建Config文件、搭建混合信号原理图,并分享提高仿真效率的技巧和常见问题排查方法,帮助工程师掌握这一关键芯片设计验证技术。

weixin_29246195的博客 986

中文语料库有哪些

中文自然语言处理开放平台 由中国科学院计算技术研究所·数字化室&软件室创立一个研究自然语言处理的一个平台,里面包含有大量的训练测试语料。 语料库:http://www.nlp.org.cn/docs/doclist.php?cat_id=9&type=15 文本语料库:http://www.nlp.org.cn/docs/doclist.php?cat_id=16&amp...

飘过的春风 2万+

吃透Chisel语言.04.Chisel基础(一)——信号类型和常量

开始肯定是介绍Chisel的基础内容了,《Chisel基础》这一部分主要会介绍数字设计中的两个基本组件:组合电路和触发器。这俩基本组件都不复杂,但是组合在一起就可以得到规模很大、功能也很强大的数字电路了。 第一部分我们就简单地看看Chisel中的信号类型和常量,在上一篇文章中也有相关介绍,其中还包括和Verilog之间的对比。......

github-3rr0r的博客 3822

MTK平台高效部署Qwen2.5大模型:从转换到推理全流程解析

本文详细解析了在MTK平台上高效部署Qwen2.5大模型的全流程,涵盖从环境准备、模型转换与量化,到编译部署与上机推理。重点介绍了如何利用MTK GAI部署工具包进行模型转换和量化,以适配MTK硬件,并最终在设备上成功运行Qwen2.5模型,为边缘侧AI应用提供实践指南。

weixin_29041195的博客 503

中文语料库

https://www.jianshu.com/p/206caa232dedhttps://blog.youkuaiyun.com/m0epNwstYk4/article/details/78840688http://www.sogou.com/labs/resource/cs.php

JiaJia 4375

【3DSlicer】基于心脏ct影像重建3d模型及导出

软件:3DSlicer4.11 基于心脏ct影像重建3d模型

Liuees的博客 1万+

国内外最好的语料库汇总

语料在语言学科研究和深度学习中都至关重要,下面对常用的语料库资源进行总结:部分信息来源于其他博客,但是本文会保持持续更新Open Speech and Language Resources http://www.openslr.org/resources.php更新(2020年6月10):若干开源语音数据库: https://blog.ailemon.me/2018/11/21/free-open-source-chinese-speech-datasets/更新2020/10/23AISHELL-3 高保

3万+

JavaFX 概述

要从 JavaFX 中充分受益,了解 JavaFX 的设计方式以及对 JavaFX 包含的功能有一个很好的概述是很有用的。本文的目的是为您提供 JavaFX 概述。本文将首先介绍一般的 JavaFX 设计,然后介绍 JavaFX 中的各种特性。如果您熟悉 Flash/Flex,您会发现 JavaFX 在某种程度上受到了 Flash/Flex 的启发。JavaFX 中也有一些相同的想法。一般来说,JavaFX 应用程序包含一个或多个对应于窗口的阶段。每个阶段都有一个场景。

2012年开始工作,全栈开发老兵,目前已是一个老师,分享这么多年的心得体会 406

化工仿真软件:gPROMS二次开发_(1).gPROMS基础知识

在gPROMS中,模型是通过定义变量、参数和方程来创建的。模型可以是简单的单元操作,如换热器、反应器,也可以是复杂的系统,如整个化工流程。变量是模型中表示状态或输出的量。在gPROMS中,变量需要显式定义其类型和单位。# 定义变量VAR# 温度变量,单位为K# 压力变量,单位为Pa# 组分摩尔分数,数组变量参数是模型中表示常量或初始条件的量。参数同样需要定义其类型和单位。# 定义参数PAR# 理想气体常数,单位为J/(mol·K)# 反应器体积,单位为m^3# 初始摩尔数。

kkchenjj的博客 615

果壳网科学人文章采集爬虫分享

大数据时代必备技能 - 神箭手云爬虫 -一站式云端通用爬虫开发平台 神箭手云爬虫多样化采集网页内容,快速产生大量而优质的内容。 1.打开神箭手云爬虫官网 2.创建爬虫任务 (1) 在首页点击“爬虫市场”,在神箭手云市场中搜索果壳网; (2)找到果壳网科学人文章采集爬虫,点击“免费获取”; 3.管理爬虫 成功获取果壳网科学人文章采集爬虫

qq_35994328的博客 1027

迟滞比较器原理及计算

为什么要用迟滞比较器 在讲迟滞比较器之前,我们先看一个案例。 在产品设计中常常需要用到电机,而电机在从运转到停止过程中需要泄放能量,这种能量大部分以电压的形式反馈回电源母线(Vbus)导致Vbus母线电压升高,特别是功率大又转速快的电机需要急刹时,产生的反馈电压更高,严重时可能导致母线上其他器件的损坏。 为了防止将电机反馈的能量泄放掉,我们需要设计一个电路来检测母线电压,当母线电压高于某一安全阈值时,打开MOSFET Q1将母线上的能量通过电阻R5以热的形式消耗掉。 假如用一般的比较器,设计如下: Vbu

sinat_15677011的博客 2万+

针对搜索引擎爬虫的欺骗式SSR

玩Google Webmasters的可能会有这种经历。自己开发的app用了Vue/React,写完后用Fetch as Google一爬傻眼了,爬不到东西。 网上搜解决方案出来的都是一堆额外的SSR框架,要上node,还看起来麻烦的要死。对于已经完成的项目,为了让搜索引擎爬虫能爬几个页面,又是改前端代码,又是改后端语言真的是郁闷。 一种...

weixin_34383618的博客 954

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

搜索引擎-语料库

语料库通常指为语言研究收集的、用电子形式保存的语言材料,由自然出现的书面语或口语的样本汇集而成,用来代表特定的语言或语言变体。经过科学选材和标注、具有适当规模的语料库能够反映和记录语言的实际使用情况。人们通过语料库观察和把握语言事实,分析和研究语言系统的规律。语料库已经成为语言学理论研究、应用研究和语言工程不可缺少的基础资源。语料库有多种类型,确定类型的主要依据是它的研究目的和用途,这一点往往能够

John.Deng的专栏 2052

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

搜索引擎白给你shell

经典的用户名密码'or'='or''or'1'='1网上好多这样的文章我的只不过是来个小总结,恩其实光是总结还不够,因为我写的还不是很全面。其实搜索这些漏洞我们必须要先连接关于搜索引擎的一些语法下面给大家介绍一下inurl: 用于搜索网页上包含的URL. 这个语法对寻找网页上的搜索,帮助之类的很有用. intext: 只搜索网页<body>部分中包含的文字(也就是...

weixin_33726318的博客 620

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

SSR(服务器渲染)和BSR(客户端渲染)及 SEO(搜索引擎优化)

SSR:服务端渲染 M+V发生在服务器端, 对营销推广要求较高的产品,会使用SSR,比如企业官网 1) 服务器的压力更大 2) 页面访问和显示速度更快(DOM少) 3) 有利于SEO搜索引擎优化(有利于公司品牌和业务的推广) 4) 前端不分离,对后端工程师要求更高,工作量更大 5) 功能比较简单的产品,交互简单的产品 BSR:客户端渲染 M+V发生在客户端 对营销推广要求不高的产品,使用BSR,比如管理系统 1)客户端压力较大 2)页面加载速度更慢(DOM多) 3)不利于SEO优化 4)前后端分离,便于

qq_44951057的博客 881

一个朴素的搜索引擎实现

今天我们要使用 Lucene 来实现一个简单的搜索引擎,我们要使用上一节爬取的果壳网语料库来构建索引,然后在索引的基础上进行关键词查询。上一节果壳网的语料库放在了 Red...

codehole_的博客 753

第一章 获取语料库

1.获取文本语料通过import nltk.book 访问定义好的文本通过nltk.corpus.gutenberg.fileids()访问古藤堡项目的文件from nltk.corpus import gutenburg        emma=gutenburg.fileids()       print(emma)  emma=gutenburg.words('austen-emma.txt...

u011588619的博客 2442
上一篇: 字节跳动面试题 —— 史莱姆变形计
下一篇: 5折抢购最后一天 | 戴尔顶级配置电脑,限时秒!
codehole_
博客等级 码龄7年 34粉丝 132原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值