LLM应用实战-财经新闻自动聚合

news/2024/12/16 13:37:19/文章来源:https://www.cnblogs.com/mengrennwpu/p/18609896

1. 背景

这段时间项目比较忙,所以本qiang~有些耽误了学习,不过也算是百忙之中,抽取时间来支撑一个读者的需求,即爬取一些财经网站的新闻并自动聚合。

该读者看了之前的《AI资讯的自动聚合及报告生成》文章后,想要将这一套流程嵌套在财经领域,因此满打满算耗费了2-3天时间,来完成了该需求。

注意:爬虫不是本人的强项,只是一丢丢兴趣而已; 其次,本篇文章主要是用于个人学习,客官们请勿直接商业使用。

2. 面临的难点

1. 爬虫框架选取: 采用之前现学现用的crawl4ai作为基础框架,使用其高阶技能来逼近模拟人访问浏览器,因为网站都存在反爬机制,如鉴权、cookie等;

2. 外网新闻: 需要kexue上网;

3. 新闻内容解析: 此处耗费的工作量最多,并不是html的页面解析有多难,主要是动态页面加载如何集成crawl4ai来实现,且每个新闻网站五花八门。

3. 数据源

数据源

url

备注

lian

https://www.cls.cn/depth?id=1000

https://www.cls.cn/depth?id=1003

https://www.cls.cn/depth?id=1007

1000: 头条,

1003: A,

1007: 环球

huang

https://finance.ifeng.com/shanklist/1-64-/

 

lang

https://finance.sina.com.cn/roll/#pageid=384&lid=2519&k=&num=50&page=1

https://finance.sina.com.cn/roll/#pageid=384&lid=2672&k=&num=50&page=1

2519: 财经

2672: 美股

qiu时报

https://finance.huanqiu.com

 

zaobao

https://www.zaobao.com/finance/china

https://www.zaobao.com/finance/world

国内及世界

fox

https://www.foxnews.com/category/us/economy

https://www.foxnews.com//world/global-economy

美国及世界

cnn

https://edition.cnn.com/business

https://edition.cnn.com/business/china

国内及世界

reuters

https://www.reuters.com/business

 

4. 部分源码

为了减少风险,本qiang~只列出财lian社网页的解析代码,读者如想进一步交流沟通,可私信联系。

代码片段解析:

1. schema是以json格式叠加css样式的策略,crawl4ai基于schema可以实现特定元素的结构化解析

2. js_commandsjs代码,主要用于模拟浏览新闻时的下翻页 

import asyncio
from crawl4ai import AsyncWebCrawler
from crawl4ai.extraction_strategy import JsonCssExtractionStrategy
import json
from typing import Dict, Any, Union, List
import os
import datetime
import re
import hashlibdef md5(text):m = hashlib.md5()m.update(text.encode('utf-8'))return m.hexdigest()def get_datas(file_path, json_flag=True, all_flag=False, mode='r'):"""读取文本文件"""results = []with open(file_path, mode, encoding='utf-8') as f:for line in f.readlines():if json_flag:results.append(json.loads(line))else:results.append(line.strip())if all_flag:if json_flag:return json.loads(''.join(results))else:return '\n'.join(results)return resultsdef save_datas(file_path, datas, json_flag=True, all_flag=False, with_indent=False, mode='w'):"""保存文本文件"""with open(file_path, mode, encoding='utf-8') as f:if all_flag:if json_flag:f.write(json.dumps(datas, ensure_ascii=False, indent= 4 if with_indent else None))else:f.write(''.join(datas))else:for data in datas:if json_flag:f.write(json.dumps(data, ensure_ascii=False) + '\n') else:f.write(data + '\n')class AbstractAICrawler():def __init__(self) -> None:passdef crawl():raise NotImplementedError()class AINewsCrawler(AbstractAICrawler):def __init__(self, domain) -> None:super().__init__()self.domain = domainself.file_path = f'data/{self.domain}.json'self.history = self.init()def init(self):if not os.path.exists(self.file_path):return {}return {ele['id']: ele for ele in get_datas(self.file_path)}def save(self, datas: Union[List, Dict]):if isinstance(datas, dict):datas = [datas]self.history.update({ele['id']: ele for ele in datas})save_datas(self.file_path, datas=list(self.history.values()))async def crawl(self, url:str, schema: Dict[str, Any]=None, always_by_pass_cache=True, bypass_cache=True,headless=True,verbose=False,magic=True,page_timeout=15000,delay_before_return_html=2.0,wait_for='',js_code=None,js_only=False,screenshot=False,headers={}):extraction_strategy = JsonCssExtractionStrategy(schema, verbose=verbose) if schema else Noneasync with AsyncWebCrawler(verbose=verbose, headless=headless, always_by_pass_cache=always_by_pass_cache, headers=headers) as crawler:result = await crawler.arun(url=url,extraction_strategy=extraction_strategy,bypass_cache=bypass_cache,page_timeout=page_timeout,delay_before_return_html=delay_before_return_html,wait_for=wait_for,js_code=js_code,magic=magic,remove_overlay_elements=True,process_iframes=True,exclude_external_links=True,js_only=js_only,screenshot=screenshot)assert result.success, "Failed to crawl the page"if schema:res = json.loads(result.extracted_content)if screenshot:return res, result.screenshotreturn resreturn result.htmlclass FinanceNewsCrawler(AINewsCrawler):def __init__(self, domain='') -> None:super().__init__(domain)def save(self, datas: Union[List, Dict]):if isinstance(datas, dict):datas = [datas]self.history.update({ele['id']: ele for ele in datas})save_datas(self.file_path, datas=datas, mode='a')async def get_last_day_data(self):last_day = (datetime.date.today() - datetime.timedelta(days=1)).strftime('%Y-%m-%d')datas = self.init()return [v for v in datas.values() if last_day in v['date']]class CLSCrawler(FinanceNewsCrawler):"""财某社新闻抓取"""def __init__(self) -> None:self.domain = 'cls'super().__init__(self.domain)self.url = 'https://www.cls.cn'async def crawl_url_list(self, url='https://www.cls.cn/depth?id=1000'):schema = {'name': 'caijingwang toutiao page crawler','baseSelector': 'div.f-l.content-left','fields': [{'name': 'top_titles','selector': 'div.depth-top-article-list','type': 'nested_list','fields': [{'name': 'href', 'type': 'attribute', 'attribute':'href', 'selector': 'a[href]'}]},{'name': 'sec_titles','selector': 'div.depth-top-article-list  li.f-l','type': 'nested_list','fields': [{'name': 'href', 'type': 'attribute', 'attribute':'href', 'selector': 'a[href]'}]},{'name': 'bottom_titles','selector': 'div.b-t-1 div.clearfix','type': 'nested_list','fields': [{'name': 'href', 'type': 'attribute', 'attribute':'href', 'selector': 'a[href]'}]}]}js_commands = ["""(async () => {{await new Promise(resolve => setTimeout(resolve, 500));const targetItemCount = 100;let currentItemCount = document.querySelectorAll('div.b-t-1 div.clearfix a.f-w-b').length;let loadMoreButton = document.querySelector('.list-more-button.more-button');while (currentItemCount < targetItemCount) {{window.scrollTo(0, document.body.scrollHeight);await new Promise(resolve => setTimeout(resolve, 1000));if (loadMoreButton) {loadMoreButton.click();} else {console.log('没有找到加载更多按钮');break;}await new Promise(resolve => setTimeout(resolve, 1000));currentItemCount = document.querySelectorAll('div.b-t-1 div.clearfix a.f-w-b').length;loadMoreButton = document.querySelector('.list-more-button.more-button');}}console.log(`已加载 ${currentItemCount} 个item`);return currentItemCount;}})();"""]wait_for = ''results = {}menu_dict = {'1000': '头条','1003': 'A股','1007': '环球'}for k, v in menu_dict.items():url = f'https://www.cls.cn/depth?id={k}'try:links = await super().crawl(url, schema, always_by_pass_cache=True, bypass_cache=True, js_code=js_commands, wait_for=wait_for, js_only=False)except Exception as e:print(f'error {url}')links = []if links:links = [ele['href'] for eles in links[0].values() for ele in eles if 'href' in ele]links = sorted(list(set(links)), key=lambda x: x)results.update({f'{self.url}{ele}': v for ele in links})return resultsasync def crawl_newsletter(self, url, category):schema = {'name': '财联社新闻详情页','baseSelector': 'div.f-l.content-left','fields': [{'name': 'title','selector': 'span.detail-title-content','type': 'text'},{'name': 'time','selector': 'div.m-r-10','type': 'text'},{'name': 'abstract','selector': 'pre.detail-brief','type': 'text','fields': [{'name': 'href', 'type': 'attribute', 'attribute':'href', 'selector': 'a[href]'}]},{'name': 'contents','selector': 'div.detail-content p','type': 'list','fields': [{'name': 'content', 'type': 'text'}]},{'name': 'read_number','selector': 'div.detail-option-readnumber','type': 'text'}]}wait_for = 'div.detail-content'try:results = await super().crawl(url, schema, always_by_pass_cache=True, bypass_cache=True, wait_for=wait_for)result = results[0]except Exception as e:print(f'crawler error: {url}')return {}return {'title': result['title'],'abstract': result['abstract'],'date': result['time'],'link': url,'content': '\n'.join([ele['content'] for ele in result['contents'] if 'content' in ele and ele['content']]),'id': md5(url),'type': category,'read_number': await self.get_first_float_number(result['read_number'], r'[-+]?\d*\.\d+|\d+'),'time': datetime.datetime.now().strftime('%Y-%m-%d')}async def get_first_float_number(self, text, pattern):match = re.search(pattern, text)if match:return round(float(match.group()), 4)return 0async def crawl(self):link_2_category = await self.crawl_url_list()for link, category in link_2_category.items():_id = md5(link)if _id in self.history:continuenews = await self.crawl_newsletter(link, category)if news:self.save(news)return await self.get_last_day_data()if __name__ == '__main__':asyncio.run(CLSCrawler().crawl())

5. 总结

一句话足矣~

开发了一款新闻资讯的自动聚合的工具,基于crawl4ai框架实现。

有问题可以私信或留言沟通!

6. 参考

(1) Crawl4ai: https://github.com/unclecode/crawl4ai

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/853756.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

减少延迟时间的方法

减少延迟时间的方法 ‍ ​​ ‍一、回顾 重点:延迟时间就是磁头在某一磁道上开转的时间 盘片一直在旋转个不停 机械硬盘的数据读取以一个扇区为单位 物理上相邻的扇区并不能连续读数据,因为磁头读入一个扇区的数据后还需要一小段时间来处理,并不能紧接着读取相邻的扇区的数据…

Win电脑端有什么好用的备忘录便签推荐?

一、sticky notes 中文名叫便笺,就是Windows电脑系统自带的便笺,打开即可直接使用,无需安装。 它是一个一个彩色便利贴形式展现的,可以记录文字、添加图片,适合记录一些简单的信息。 不支持一直悬挂在电脑桌面上显示,也不支持设置提醒时间,想要同步到手机端使用,也有点…

设备的分配与回收

设备的分配与回收 ‍ ​​ ‍一、设备分配时的考虑因素 ​​ (一)设备的固有属性独占设备:一个时段只能分配给一个进程(如打印机) 共享设备:可同时分配给多个进程使用(如磁盘),各进程往往是宏观上同时共享使用设备,而微观上交替使用。 虚拟设备:采用 SPOOLing 技术将…

GitHub项目迁移到GitLab

GitHub项目迁移到GitLab 1.克隆GitHub项目到本地 [root@gitclient ~]# mkdir gitrepos [root@gitclient ~]# cd gitrepos [root@gitclient gitrepos]# git init . hint: Using master as the name for the initial branch. This default branch name hint: is subject to chang…

极狐GitLab 正式发布安全补丁版本 17.6.2、17.5.4、 17.4.6

本分分享极狐GitLab 补丁版本 17.6.2, 17.5.4, 17.4.6 的详细内容。这几个版本包含重要的缺陷和安全修复代码,我们强烈建议所有私有化部署用户应该立即升级到上述的某一个版本。对于极狐GitLab SaaS,技术团队已经进行了升级,无需用户采取任何措施。 参考资料GitLab 专业升级…

IO应用程序接口设备驱动程序接口

IO应用程序接口&设备驱动程序接口 ‍ ​​ ‍一、输入/输出应用程序接口 背景:在设备独立软件层向上提供各种各样的输入/输出应用程序接口的原因是: 用户层的应用程序无法用一个统一的系统调用接囗来完成所有类型设备的 I/O ​​ ‍ 三种输入/输出应用程序接口:字符设备…

IO核心子系统

IO核心子系统 I/O 核心子系统要实现的功能就是中间三层要实现的功能。 前言:本节仅作介绍和导学,主要列举 I/O 子系统实现的相关功能,详细跳转至各对应节 ​​ ‍​​ ‍ 一、I/O 调度 用某种算法确定一个好的顺序来处理各个 I/O 请求。(类比进程调度) 如:磁盘调度(先来…

【日记】天气好好,然后打了两天游戏(562 字)

正文昨天和今天打了两天游戏,笑死。黑神话发布更新了,多打了几次虎先锋,今天晚上才过了二郎神。二郎神是真难啊。不过之后的法天相地战也是真帅啊。幸好之前没有看攻略被剧透一脸。除此之外好像就没做什么了。太懒了。中午吃饭,店家问我在读书还是工作了。后面我们聊起来。…

如何让 localStorage 数据实现实时响应

重大事项 📣 :重大事项提前通知!快来围观,不容错过! 极限科技 一直致力于为开发者和企业提供优质的开源工具,提升整个技术生态的活力。除了维护国内最流行的分词器 analysis-ik 和 analysis-pinyin,也在不断推动更多高质量开源产品的诞生。 在极限科技成立三周年之际,…

loadSend:免费开源局域网数据传输工具 全平台支持 传输工具

前言 不同系统的电脑、手机,文件传输有没有简单一点的方法? 手机是iPhone,电脑是Windows,如何更快捷传输文件呢? 我们最常用和用得最多的文件传输工具可能就是微信以及 QQ 了吧! 其实,如果只是在局域网内,用微信这一类聊天工具来传输文件并不算特别合适,除了可能存在的…

焦作本地在线教育系统价格

近年来,在线教育的普及使得传统教培模式受到了新的挑战。无论是大型教育集团,还是地方性的教培中心,纷纷转型线上,寻求更为灵活的盈利方式和发展机遇。在众多竞争者中,了解并运用合适的在线教育系统对维持市场地位至关重要。图源 凸知@www.tuzhi.ltd对于许多像焦作地区教育…

项目管理看板:实现任务透明化与实时跟踪

一、项目管理看板的定义与背景 1.1 什么是项目管理看板? 项目管理看板(Project Management Kanban)是一种可视化的任务管理工具,旨在帮助团队或项目管理者清晰地展示项目任务的状态,并对任务的进展进行实时跟踪。看板通常分为若干列,每一列代表任务的不同阶段(例如:待办…