基于bash while read循环的过往Issue链接爬取需求及优化建议
爬取过往Issue链接的脚本优化建议
原脚本存在的问题
- URL未加引号:如果链接包含
&、空格等特殊字符,wget $url会解析失败直接报错 - 重复爬取风险:循环中直接覆盖
list文件,未区分已爬取和待爬取链接,会反复爬取同一页面 - 多管道低效:多次调用
grep、sed,进程开销大,处理大量页面时速度偏慢 - 文件读写混乱:循环读取
list的同时重写该文件,会导致文件指针异常,可能出现漏读或重复读取链接的情况
优化后的Shell实现方案
下面是更高效稳定的版本,核心是拆分待爬取列表和已爬取列表,避免重复操作,同时合并筛选逻辑减少管道调用:
初始化文件
# 初始化待爬取列表,放入起始链接 echo "https://abc.xyz/issues/" > to_crawl # 初始化已爬取列表(空文件) touch crawled
爬取循环脚本
while [ -s to_crawl ]; do # 取出待爬取列表的第一条链接,同时从列表中移除 read url < to_crawl sed -i 1d to_crawl # 标记该链接为已爬取 echo "$url" >> crawled # 爬取页面、提取目标链接、过滤重复项后加入待爬列表 wget -q "$url" -O - | awk ' # 直接匹配目标格式的链接:https://abc.xyz/issues/yyyy/mm/dd match($0, /href="(https:\/\/abc\.xyz\/issues\/[0-9]{4}\/[0-9]{2}\/[0-9]{2})"/, link_arr) { print link_arr[1] } ' | sort -u \ | grep -vxFf crawled \ # 排除已爬取的链接 | grep -vxFf to_crawl \ # 排除已在待爬列表的链接 >> to_crawl done # 最终所有符合要求的链接都保存在crawled文件中 cat crawled
关键优化点说明
- 区分待爬/已爬列表:彻底避免重复爬取同一页面,大幅提升爬取效率
- 精准匹配目标链接:用awk直接匹配
https://abc.xyz/issues/yyyy/mm/dd格式,跳过无关链接,减少无效处理 - URL加双引号:兼容带特殊字符的链接,避免解析错误
- 减少管道调用:用awk一次性完成提取和筛选,替代原脚本多次
grep+sed的组合,降低进程开销 - 原子化处理待爬列表:每次只取出一条链接并移除,避免循环中文件内容变化导致的读取异常
可选简化方案(用curl替代wget)
如果习惯用curl,把wget -q "$url" -O -换成curl -s "$url"即可,效果完全一致:
curl -s "$url" | awk '...'
内容的提问来源于stack exchange,提问作者cimba8
相关产品推荐
相关产品推荐

