自动采集编写(个性化诉求,最简单的方式就是你感兴趣(组图))
优采云 发布时间: 2022-03-21 02:12自动采集编写(个性化诉求,最简单的方式就是你感兴趣(组图))
前言
相信每个技术人员都有定期获取技术信息的愿望,获取方式有很多种。比如使用新闻APP、订阅RSS、参加行业会议、深入技术社区、订阅期刊、公众号等都是可选的。通过这些方式查看信息的成本非常低,有一种“开箱即用”的感觉。但缺点也很明显。有点像“大班”,可以满足一类人的需求,但很难更好地满足每个参与者的个性化需求。通过这些方法,真正得到你需要的信息的成本并不低(虽然智能推荐正在迭代以满足个性化需求,但与预期仍有很大差距)。
核心问题是以上两个类路径都不是很懂你(理解你的意图和需求)。而且您需要一种理解您并且不太昂贵的方式。
一、关于技术信息获取DIY的框架思考
相信在相当长的一段时间内,获取个性化信息最合适的方式仍然是工具和人工的结合。与纯工具算法推荐相比,部分付费信息渠道在(智能)工具的基础上人工筛选和处理信息,质量会更好。如果你是程序员,自己写一些小爬虫,将自己的喜好和智慧注入其中,是一种低成本的了解你的方式。通过这种方式,您将获得极大的自我控制感。在本文中,作者将重点介绍这种方法。值得提醒的是,本文所涉及的内容仅用于学习和讨论技术,不得用于非法用途。
具体分为四个部分(如图1.1):
图1.1
一、控制自己的信息来源
您可以根据自己的经验,在合法合规的前提下选择来源。这种选择的维度可以是多种多样的,包括质量可靠性、前瞻性信息、兴趣匹配、研究方向匹配、信息产生频率、信息新颖性等。
二、编写自己的采集和过滤算法
选择几个 采集 通道后,您可以编写自己的 采集 和过滤算法。采集时间段、过滤规则、想要的内容项等等都在你自己的掌控之中。如果你对数据处理、人工智能等有很好的了解,相信还有更大的发挥空间。
三、自行控制阅读和交互体验
由于阅读是一个长期的过程,实际上对高质量体验的需求非常强烈。不舒服的阅读体验非常不利于快速获取信息,甚至打消获取信息的兴趣。比如下面两张图片中,图片1.2左边是标题的信息界面,右边是微信阅读的阅读界面。
图1.2
相比之下,作为一个读者,我个人更喜欢微信阅读的简单,而不是标题那些次要元素的分散注意力。
四、自行控制迭代优化
在一定程度上既是信息流的消费者又是信息流控制者的好处是可以站在结果环节独立评价信息获取的全过程,并回溯到上一个环节,从而形成正向闭环。
这样做有什么好处?
首先是获取有价值的信息。
这个不用说了。
二是有助于提高获取信息的能力。
以技术人员为例,通过这样做,他们可以更高效、持续地获取满足个人需求的高价值信息,并在保持对外部技术世界持续关注的同时获得持续的成长和改进。
1)关于信息来源:您将总结出最有价值信息的来源列表,提高信息获取效率,以更快的速度获取相对可靠的信息。
2)关于信息处理:你会沉淀自己简单或复杂的信息采集和筛选算法,提高辨别信息的能力,增强处理信息的能力。
3)关于信息体验:您将获得适合自己的信息获取、阅读和互动体验,增强阅读兴趣,减少疲劳。
三是有利于技术探索,提高技术应用能力。
在这个过程中,实际上是一个用技术解决实际问题的探索过程,可以作为技术甚至产品建设探索的试验田。比如有很多公司在尝试和应用 Flutter 的技术,但是你做的项目暂时还是用 Electron 做的,目前没有迁移到 Flutter 的计划。那么如果你对Flutter感兴趣,可以尝试用Flutter用采集得到的技术资料做一个APP,先测试一下怎么用(只是一个“栗子”,如果你真的是有兴趣的,后面有个彩蛋,继续往下看,看看能不能找到?)。这相当于在业余初期做一些储备和练习。
二、技术信息获取DIY实践探索
上面的就这么啰嗦了,讲讲吧。让我们实际抓取一些技术信息。要捕获的内容有多种形式。有的由内容服务器直接渲染到 HTML 页面上,有的通过页面中的 JavaScript 请求数据,然后渲染。
先看第一个。
1、从 HTML 页面爬取内容
第一步是信息来源的选择。
不然就找一家比较有代表性的互联网公司BAT,看看他们有什么有价值的技术资料。最好选阿里巴巴,知名度比较高的(很愿意跟业界分享自己的技术),因为知名度高的可能比较容易找。他们有一个云栖社区,有一个专栏叫阿里科技(),是一个定期更新的专栏,文章质量不错。界面如下。
图2.1
第二步是采集和信息的筛选。
假设我们要爬取最近一周阿里科技栏目下新发布的文章。我们主要获取它的标题、文章链接地址、发布时间和文章简介,希望只抓取最近7天内发布的文章。即爬取的预期结果如图2.2所示。
图2.2
目标明确了,接下来就是如何实现了,我选择使用Node.js。这里需要介绍两个工具:request-promise() 和cheerio()。所以首先需要使用yarn init命令创建一个项目,然后使用yarn add request request-promise Cheerio命令安装这些依赖模块。
关于request-promise,官方的介绍是:
支持 Promise 的简化 HTTP 请求客户端“请求”。由蓝鸟提供支持。
使用 request-promise,你可以很容易的抓取页面的 HTML,如下:
constrp=require('请求-承诺');
rp('//省略地址
.then(函数(htmlString){
//处理html...
})
.catch(函数(错误){
//爬取失败...
});
抓到HTML之后,我们还是希望对其进行处理,提取出标题、文章链接地址和文章介绍等我们需要的信息。这时候就需要用到另一个工具——cheerio。将它与 request-promise 结合使用,您基本上可以像使用 jQuery 一样处理获取的 HTML。因为cheerio 实现了jQuery 的核心子集。两者结合使用如下:
`constrp=require('request-promise');
constcheerio=require('cheerio');
consttargetURL='//地址省略
常量选项={
uri:targetURL,
变换:(主体)=>{
returncheerio.load(body);
}
};
函数getArticles(){
rp(选项)
.then(($)=>{
//ProcesshtmllikeyouwouldwithjQuery...
console.log($('title').text());
})
.catch((错误)=>{
//爬行失败或Cheeriochoked...
});
}
//入口
获取文章();
`
在上面的代码中,
console.log($('title').text())
它将注销页面标题标签内的文本,就像使用 jQuery 操作页面 DOM 一样。
然后我们就可以用Chrome打开AliTech()页面,使用Chrome DevTools轻松找到文章标题对应的HTML元素(如图2.3)。然后通过将上面的代码添加到
console.log($('title').text())
将此行替换为:
console.logconsole.log($('.yq-new-itemh3a').eq(1).text())($('.yq-new-itemh3a').eq(1) 。文本())
因此注销技术信息之一的标题文章。
图2.3
以此类推,文章链接地址和文章配置文件可以通过同样的方式获得。但是我们也想获取每个文章的发布时间,但是当前页面没有,怎么办?点击每一个文章的链接,我们发现文章里面都有这个信息(如图2.4)。那么,实现思路就有了.每次抓取到一个文章的链接后,抓取链接地址,抓取文章的释放时间。
图2.4
另外,由于 Promise 在代码中使用过多后看起来有点难看,我们将其改为使用 async 和 await。并将捕获的信息写入 JSON 文件 (result.json)。最终确定的demo代码如下:
/**
*爬取技术资料学习实例1
*/
constfs=require('fs');
constrp=require('请求-承诺');
constcheerio=require('cheerio');
consttargetURL='';//地址省略
constmaxDeltaDay=7;
/**
* 从登录页面抓取技术信息
*@param{string}url - 抓取的着陆页的 URL
*@param{number}maxDeltaDay - 从当前时间获取信息的天数
*/
asyncfunctiongetArticles(url,maxDeltaDay){
constoptions=generateOptions(url);
常量$=awaitrp(选项);
constelements=$('.yq-new-itemh3a');
//获取收录文章标题、链接等的标签
解释=[];
constpromises=[];
元素.map((index,el)=>{
常量$el=$(el);
constlinkObj={};
// 获取标题和链接
linkObj.title=$el.text();
constlink=$el.attr('href');
linkObj.link=`${link}`;
//进程文章简介
letbrief=$el.parent().parent().find('.new-desc-two').text();
简介=brief.replace(/\s*/g,'');
linkObj.brief=简介;
承诺.push(
getDeltaDay(linkObj.link).then((deltaDay)=>{
如果(三角洲日{
如果(结果。长度){
控制台.log(结果);
结果.sort((a,b)=>{
返回a.deltaDay-b.deltaDay;
})
fs.writeFileSync('./result.json',JSON.stringify(result));
}
});
}
/**
* 生成用于启动请求-承诺获取的选项参数
*@param{string}url - 要抓取的目标地址
*/
函数生成选项(网址){
返回{
URI:网址,
变换:(主体)=>{
returncheerio.load(body);
}
};
}
/**
*获取文章的发布时间
*@param{string}文章 的 URL 地址
*/
异步函数getDeltaDay(网址){
constoptions=generateOptions(url);
常量$=awaitrp(选项);
const$time=$('.yq-blog-detail.b-time');
constdateTime=$time.text();
letdeltaDay=(newDate()-newDate(dateTime))/(24*60*60*1000);
deltaDay=deltaDay.toFixed(1);
返回deltaDay;
}
//入口
getArticles(targetURL,maxDeltaDay);
其中,getDeltaDay函数用于处理发布时间捕获。我们的最终目标不是捕捉文章的发布时间,而是看发布时间和当前时间的差值是否在7天之内。当然,如果要进一步过滤,也可以抓取阅读数、点赞数、采集数等来判断。
2、爬取数据接口中的内容
以上是静态 HTML 页面上的数据抓取。我们来看第二个,抓取界面中的数据。以下是知名技术社区掘金的数据捕获示例。
图2.5
如图2.5所示,掘金的信息分为推荐、后端、前端、Android、iOS、人工智能、开发工具、代码寿命、阅读等多个类别。通过Chrome DevTools查看网络请求我们发现传递了页面中的文章列表数据。并且每个category下的文章列表数据来自同一个接口,但是在发出请求时,Request Payload中的variables下的category(category ID)字段是不同的,如图2.6、图2.7.
图2.6
图2.7
因此,总体思路是创建一个类别名称和类别ID的映射,并使用不同的类别ID来分别调用上述接口。具体爬虫还是使用上面使用的request-promise。由于事先不复杂,我就不过多解释了,直接贴代码:
/**
*爬取技术资料学习实例2
*/
constrp=require('请求-承诺');
constfs=require('fs');
// 类别对应的ID
constcategoryIDMap={
'推荐':'',
“后端”:“5562b419e4b00c57d9b94ae2”,
'前端': '5562b415e4b00c57d9b94ac8',
'安卓':'5562b410e4b00c57d9b94a92',
'iOS':'5562b405e4b00c57d9b94a41',
'人工智能':'57be7c18128fe1005fa902de',
'开发工具': '5562b422e4b00c57d9b94b53',
'代码生活':'5c9c7cca1b117f3c60fee548',
“阅读”:“5562b428e4b00c57d9b94b9d”
};
/**
*用于生成request-promise的options参数
*@param{string}categoryID-类别ID
*/
函数生成选项(类别 ID){
返回{
方法:'POST',
uri:'//省略地址
身体:{
'操作名称':'',
'询问':'',
'变量':{
'标签':[],
'类别':类别ID,
“第一”:20,
'后':'',
“订单”:“流行”
},
'扩展':{
'询问':{
'id': '653b587c5c7c8a00ddf67fc66f989d42'
}
}
},
json:真,
标题:{
'X-特工':'绝金/网络'
},
}
};
/**
*获取某类下的信息数据
*@param{string}categoryID-类别ID
*/
异步函数getArtInOneCategory(categoryID,categoryName){
constoptions=generateOptions(categoryID);
constres=awaitrp(选项);
constdata=res.data.articleFeed.items.edges;
letcurrentCategoryResult=[];
data.map((项目)=>{
constlinkObj={};
常量{
标题,
原创网址,
更新时间,
喜欢计数
}=item.node;
linkObj.title=标题;
linkObj.link=originalUrl;
linkObj.likeCount=likeCount;
linkObj.category=categoryName;
letdeltaDay=(newDate()-newDate(updatedAt))/(24*60*60*1000);
deltaDay=deltaDay.toFixed(1);
如果(三角洲日{
constcategoryID=categoryIDMap[key];
promises.push(getArtInOneCategory(categoryID,key).then((res)=>{
结果=结果.concat(res);
}));
});
Promise.all(promises).then(()=>{
fs.writeFileSync('./result2.json',JSON.stringify(result));
});
}
//入口
获取所有文章();
捕获的结果如图2.8所示,主要捕获标题、链接、点赞数、类别、当前与发布的时间差(天):
图2.8
3、爬取微信公众号内容
除了以上两类内容的抓取外,还有一种可能会遇到的更频繁的信息抓取,那就是微信公众号内容的抓取。例如,以公众号“xx早读班”的抓取为例。如果微信公众号的内容是直接从微信平台抓取的,需要登录,估计很容易被封号。因此,您可以尝试另一种方法——爬取搜狗搜索提供的微信公众号搜索结果。
首先通过%E5%89%8D%E7%AB%AF%E6%97%A9%E8%AF%BB%E8%AF%BE&ie=utf8&_sug_=y&_sug_type_=&w=01019900&sut=6202&sst0=79&lkt=0%2C0% 2C0获取公众号的英文ID。如图2.9所示。
图2.9
然后用公众号的英文ID搜索公众号最新的文章,在弹出的过滤面板中选择“一周内”点击“搜索工具”过滤掉<最近一周的@文章(如图)。2.10)。之所以使用英文ID,是为了让搜索结果只来自公众号,信息更纯粹。
图2.10
然而,不幸的是,这些数据是由服务器直接呈现在 HTML 页面中的,而不是从界面返回的。而且,在呈现这些信息之前,它必须经过几个交互步骤,如图2.10所示。所以不能像上面两种方法那样抓取数据。具体实现可以使用puppeteer。puppeteer 是 Chrome 出品的官方无头 Chrome 节点库。它提供了一系列API,可以在没有UI的情况下调用Chrome的功能。适用于爬虫、自动化处理等场景(如自动化测试)。详细使用请参考官方文档()。限于篇幅,这里不再介绍具体实现。值得注意的是,搜狗搜索做了大量的反爬工作,
1)puppteer 吃午饭的时候需要加上headless: false 选项,避免让你输入验证码。如下:
constbrowser=awaitpuppeteer.launch({
无头:假
});
2)爬取的次数尽量少,否则当你频繁爬取时,对方会要求你输入验证码,此时爬取工作无法继续。
即使注意这两点,也可能会遇到被识别为爬虫的情况。因此,正确的应该是学习木偶的一种尝试。毕竟这个工具功能相当强大,在前端自动化测试等领域潜力巨大。
三、扩展思维
以上对信息的采集做了一些具体的介绍。可以对信息进行进一步处理,以便更好地自己学习和研究。这里有一些想法。
图3.1
如图3.1所示,数据通过后台服务从消息源池采集后,可以建立一个数据库来存储数据,前端可以提供一些数据服务接口-最终商业用途。可以对数据进行处理、处理、可视化,比如直接以前端网页的形式呈现,也可以制作原生APP。甚至添加一些反馈通道来评估信息,从而从评估数据中推断出源通道的质量。
至于基于偏好控制阅读和交互体验,一般有一些通用的指导方针。比如简洁的整体风格,突出内容本身的沉浸感和无干扰感;适当的字体大小和行距;漂亮的字体;可调节和保护眼睛的背景颜色;运行平稳; 有些人一起参加,而不是单独参加。如果你对这方面感兴趣,可以参考这篇文章文章微信阅读解析(),这里不再赘述。
总结
本文首先分析了一些常见的信息获取方式的优缺点,分享了关于技术信息获取DIY的思路框架,并阐明了其价值。然后,借助三个具体的爬取案例,分析了爬取思路,并给出了一些演示代码示例。最后,我想到了这个话题的延伸,在此基础上,一个简单的产品甚至一个系统都可以DIY出来。
最后,你找到关于 Flutter 的彩蛋了吗?(图 2.2 中的第二条消息)?