如何为Python Discord爬虫机器人实现爬取链接去重?
问题
我正在用Python开发一个Discord机器人,给不支持邮件通知的站点做爬虫功能。不是专业学Python的,靠搜索和自学写了示例代码,之前用old_links = []列表实现去重,但机器人重启后已爬过的帖子会重复发送到Discord。现在改成把已发送的链接保存到本地old_links.txt文件,想每次定时运行时对比文件里的链接实现不重复发送,目前能把链接存到文件,但对比去重的功能没实现,求修改方案。
原代码:
async def test(): old_links = open("old_links.txt", "r", encoding="utf-8") while True: base_url = 'https://www.cnbc.com/world/' async with aiohttp.ClientSession() as sess: async with sess.get(base_url, headers={'user-agent': 'Mozilla/5.0'}) as res: text = await res.text() soup = bs(text, 'lxml') title = soup.find("div", attrs={"class":"LatestNews-container"}).a.text.strip() link = soup.find("div", attrs={"class":"LatestNews-container"}).a["href"] if link not in old_links: print(f"title : {title}") print(f"link : {link}") f = open("old_links.txt", "w", encoding="utf-8") f.write(f"{link}\n") f.close() else: print("No update") await asyncio.sleep(3)
解决方案
核心问题是直接把文件对象当成链接列表做判断,old_links = open("old_links.txt", "r", encoding="utf-8")得到的是文件对象,不是可迭代的链接集合,所以link not in old_links永远无法正确触发。另外原代码的写入逻辑会覆盖历史链接,每次只保留最新一条,也不符合需求。
修改步骤
- 读取文件为链接列表:启动或循环时,把文件内容读成列表,清理换行符和空行避免干扰判断。
- 安全操作文件:用
with语句自动管理文件关闭,避免资源泄漏;新增链接时,把整个更新后的列表写入文件,保留所有历史记录。 - 修正代码缩进:原代码
async with和循环内代码缩进错误,会导致语法报错,必须调整。
修改后的完整代码
import aiohttp from bs4 import BeautifulSoup as bs import asyncio async def test(): # 初始化旧链接列表,处理文件不存在的情况 try: with open("old_links.txt", "r", encoding="utf-8") as f: # 读取所有行,过滤空行并去掉换行符 old_links = [line.strip() for line in f if line.strip()] except FileNotFoundError: # 第一次运行文件不存在时,创建空列表 old_links = [] while True: base_url = 'https://www.cnbc.com/world/' async with aiohttp.ClientSession() as sess: async with sess.get(base_url, headers={'user-agent': 'Mozilla/5.0'}) as res: text = await res.text() soup = bs(text, 'lxml') # 获取最新新闻容器,增加容错判断 news_container = soup.find("div", attrs={"class":"LatestNews-container"}) if not news_container: print("未找到新闻容器") await asyncio.sleep(3) continue title = news_container.a.text.strip() link = news_container.a["href"] # 判断链接是否已存在 if link not in old_links: print(f"title : {title}") print(f"link : {link}") # 将新链接加入列表 old_links.append(link) # 写入完整的链接列表到文件 with open("old_links.txt", "w", encoding="utf-8") as f: f.write("\n".join(old_links)) else: print("No update") await asyncio.sleep(3) # 直接运行脚本时启动测试 if __name__ == "__main__": asyncio.run(test())
关键说明
- 用
try-except处理文件不存在的场景,第一次运行自动初始化空列表。 - 读取文件时用列表推导式清理无效行,避免空行导致的误判。
- 写入文件时用
"\n".join(old_links)把整个列表转成字符串,完整保留所有历史链接。 - 增加了新闻容器的存在判断,避免页面结构变化导致的报错。
内容的提问来源于stack exchange,提问作者Chozi
相关产品推荐
相关产品推荐

