最近,遇到一个需求:需要定期从一个网站的Sitemap中提取最新发布文章的URL。在网上找了很久没有找到相关的解决方案,在好几个群里也没找到相关办法,迫于无奈,决定试试通过AI来生成代码。为了避免出问题、同时对比一下各AI的效果,同时使用了好几个AI来进行操作,最后通义千问生成代码执行成功。
本文将详细介绍这次技术体验,包括花费的时间、代码功能、优化和修复过程,以及在与AI交流中学到的经验。
项目背景
需求是一个脚本,可以从指定的Sitemap索引文件中提取最新发布的文章URL。具体来说,这个脚本需要完成以下步骤:
- 下载Sitemap索引文件。
- 解析Sitemap索引文件,提取所有
post-sitemap.xml
的URL及其最后修改时间。 - 按最后修改时间逆序排序
post-sitemap.xml
文件。 - 获取最新更新的
post-sitemap.xml
文件的信息。 - 解析
post-sitemap.xml
文件,提取文章URL及其最后修改时间。 - 按日期逆序排序所有文章URL及其最后修改时间。
- 输出最新的文章地址。
这里要注意,就我自己而言实际上我在一开始并不知道提取最新的文章URL是要通过这些步骤的,我想的比较简单,只是提供sitemap地址,后台在线识别、找到第一个更新的文章即可。但是在执行的时候却出现了很多问题,例如首要的问题就是实际上在识别sitemap的时候是需要先下载sitemap的,在本地进行识别,而不是直接在网络上进行识别。当然,这对于有编程经验尤其是后端经验的人来说应该不是什么问题。而且紧跟着,就又出现了始终无法将sitemap正常下载下来的问题,而这一步也导致了其他AI都失败了,或许也不能说是失败不,因为在尝试几次后,为了节约时间就基本上没有向其他AI提供错误信息了,因此其他AI没有找到解决方案。
这里尤其要提一下,如果一个错误频繁重现,那么AI是可以“意识到”要在代码中添加调试信息的,这样作为用户的我们就可以向AI提供错误信息,帮助AI(怎么反了,不是AI帮助我们吗?)来尽快找到解决问题的方案。因此,如果在要AI生成代码的过程中,对于自己想要的功能总是不满意,或者运行出错,那么可以主动向AI提出,要求AI来加入调试代码,来生成各类错误信息。
生成代码的过程
初次尝试
一开始,对如何描述需求感到有些迷茫,尝试用简单的语言描述了需求,例如:“需要一个脚本,可以从Sitemap中提取最新文章的URL。” AI很快就生成了一段基本的脚本,但功能还不够完整。
#!/bin/bash
SITEMAP_INDEX_URL="https://littleprince.site/sitemap_index.xml"
curl -s -o sitemap_index.xml "$SITEMAP_INDEX_URL"
# ...(省略部分代码)
功能细化
意识到需要更详细地描述每个步骤。于是,逐条描述了每个功能点,并要求AI生成相应的代码。经过几次迭代,代码逐渐完善。
第二次生成的代码:
#!/bin/bash
SITEMAP_INDEX_URL="https://littleprince.site/sitemap_index.xml"
curl -s -o sitemap_index.xml "$SITEMAP_INDEX_URL"
# 解析Sitemap索引文件,提取所有post-sitemap.xml的URL及其最后修改时间
post_sitemap_data=$(xmlstarlet sel -N x="http://www.sitemaps.org/schemas/sitemap/0.9" -t -m "//x:sitemap[x:loc[contains(., 'post-sitemap')]]" -v "concat(x:lastmod, ' ', x:loc)" -n sitemap_index.xml)
# 按最后修改时间逆序排序post-sitemap.xml文件
sorted_post_sitemap_data=$(echo "$post_sitemap_data" | sort -r -k1,1)
# 获取最新更新的post-sitemap.xml文件的信息
latest_post_sitemap_line=$(echo "$sorted_post_sitemap_data" | head -n 1)
latest_post_sitemap_url=$(echo "$latest_post_sitemap_line" | awk '{print $2}')
# 下载最新更新的post-sitemap.xml文件
curl -s -o latest_post_sitemap.xml "$latest_post_sitemap_url"
# 解析post-sitemap.xml文件,提取文章URL及其最后修改时间
all_urls=$(xmlstarlet sel -N x="http://www.sitemaps.org/schemas/sitemap/0.9" -t -m "//x:url" -v "concat(x:lastmod, ' ', x:loc)" -n latest_post_sitemap.xml)
# 按日期逆序排序所有文章URL及其最后修改时间
sorted_urls=$(echo "$all_urls" | sort -r -k1,1)
# 获取第一个结果,即最新的文章URL
newAddress=$(echo "$sorted_urls" | head -n 1 | awk '{print $2}')
# 输出最新的文章地址
echo "最新的文章地址: $newAddress"
代码优化
尽管代码已经基本实现了功能,但发现了一些可以优化的地方,例如增加缓存机制、添加用户输入功能等。提出了这些优化建议,AI很快进行了调整。
最终生成的代码:
#!/bin/bash
# 设置默认的Sitemap索引URL
DEFAULT_SITEMAP_INDEX_URL="https://littleprince.site/sitemap_index.xml"
# 提示用户输入Sitemap索引URL,设置超时时间为15秒
read -t 15 -p "请输入要查询的Sitemap索引URL(默认: $DEFAULT_SITEMAP_INDEX_URL): " SITEMAP_INDEX_URL
# 如果用户没有输入任何内容,则使用默认值
if [ -z "$SITEMAP_INDEX_URL" ]; then
SITEMAP_INDEX_URL=$DEFAULT_SITEMAP_INDEX_URL
fi
# 提取网站域名作为唯一标识符
DOMAIN=$(echo "$SITEMAP_INDEX_URL" | awk -F[/:] '{print $4}')
# 定义缓存目录
CACHE_DIR="./cache/$DOMAIN"
mkdir -p "$CACHE_DIR"
# 下载Sitemap索引文件,并忽略SSL证书验证
curl -s -k -o "$CACHE_DIR/sitemap_index.xml" "$SITEMAP_INDEX_URL"
# 检查是否成功下载Sitemap索引文件
if [ ! -f "$CACHE_DIR/sitemap_index.xml" ] || [ ! -s "$CACHE_DIR/sitemap_index.xml" ]; then
echo "未能成功下载Sitemap索引文件"
exit 1
fi
# 解析Sitemap索引文件,提取所有post-sitemap.xml的URL及其最后修改时间
post_sitemap_data=$(xmlstarlet sel -N x="http://www.sitemaps.org/schemas/sitemap/0.9" -t -m "//x:sitemap[x:loc[contains(., 'post-sitemap')]]" -v "concat(x:lastmod, ' ', x:loc)" -n "$CACHE_DIR/sitemap_index.xml")
# 检查是否成功获取到post-sitemap.xml的URL
if [ -z "$post_sitemap_data" ]; then
echo "未找到任何post-sitemap.xml的URL"
exit 1
fi
# 按最后修改时间逆序排序post-sitemap.xml文件
sorted_post_sitemap_data=$(echo "$post_sitemap_data" | sort -r -k1,1)
# 获取最新更新的post-sitemap.xml文件的信息
latest_post_sitemap_line=$(echo "$sorted_post_sitemap_data" | head -n 1)
latest_post_sitemap_lastmod=$(echo "$latest_post_sitemap_line" | awk '{print $1}')
latest_post_sitemap_url=$(echo "$latest_post_sitemap_line" | awk '{print $2}')
latest_post_sitemap_file="$CACHE_DIR/post-sitemap-$(basename "$latest_post_sitemap_url")"
# 检查文件是否已存在
if [ -f "$latest_post_sitemap_file" ]; then
# 给出判断选项
echo "本地已有缓存文件: $latest_post_sitemap_file"
echo "是否使用本地缓存进行处理? (y/n)"
# 设置超时时间为10分钟
timeout=600
read -t $timeout -p "请输入 (y/n): " choice
case $choice in
y|Y)
echo "使用缓存文件: $latest_post_sitemap_file"
;;
n|N)
echo "重新下载: $latest_post_sitemap_url"
curl -s -k -o "$latest_post_sitemap_file" "$latest_post_sitemap_url"
;;
*)
echo "超时或输入无效,重新下载: $latest_post_sitemap_url"
curl -s -k -o "$latest_post_sitemap_file" "$latest_post_sitemap_url"
;;
esac
else
echo "下载新文件: $latest_post_sitemap_url"
curl -s -k -o "$latest_post_sitemap_file" "$latest_post_sitemap_url"
fi
# 检查是否成功下载post-sitemap.xml文件
if [ ! -f "$latest_post_sitemap_file" ] || [ ! -s "$latest_post_sitemap_file" ]; then
echo "未能成功下载post-sitemap.xml文件: $latest_post_sitemap_url"
exit 1
fi
# 初始化一个空数组来存储所有文章URL及其最后修改时间
all_urls=()
# 解析post-sitemap.xml文件,提取文章URL及其最后修改时间
while read -r line; do
lastmod=$(echo "$line" | awk '{print $1}')
loc=$(echo "$line" | awk '{print $2}')
# 排除首页URL
if [[ "$loc" != "https://$DOMAIN" ]]; then
all_urls+=("$lastmod $loc")
# echo "提取到的URL: $loc, 最后修改时间: $lastmod" # 调试信息
fi
done < <(xmlstarlet sel -N x="http://www.sitemaps.org/schemas/sitemap/0.9" -t -m "//x:url" -v "concat(x:lastmod, ' ', x:loc)" -n "$latest_post_sitemap_file")
# 检查是否成功获取到文章URL及其最后修改时间
if [ ${#all_urls[@]} -eq 0 ]; then
echo "未找到任何文章URL"
exit 1
else
# echo "成功获取到文章URL及其最后修改时间" # 调试信息
:
fi
# 打印所有文章URL及其最后修改时间
# echo "所有文章URL及其最后修改时间:"
# printf "%s\n" "${all_urls[@]}"
# 将所有文章URL及其最后修改时间按日期逆序排序
sorted_urls=$(printf "%s\n" "${all_urls[@]}" | sort -r -k1,1)
# 打印排序后的文章URL及其最后修改时间
# echo "排序后的文章URL及其最后修改时间:"
# echo "$sorted_urls"
# 获取第一个结果,即最新的文章URL
newAddress=$(echo "$sorted_urls" | head -n 1 | awk '{print $2}')
# 输出最新的文章地址
echo "最新的文章地址: $newAddress"
踩的坑与经验总结
在实际代码生成的过程中,其实远远不止生成了这么些次,还有很多都没有记录。
在代码实现基本功能的环节,就尝试了很久,例如前面提到的无法下载sitemap,主要是由于证书错误,但是发现证书错误这个问题就花费了很久、由AI生成了很多次代码、发送多次调试信息后才找到原因;此外,还有排序不正确,例如URL和其修改时间在抓取、分析后不对应,导致找到的日期确实是最新的修改日期,可是URL却不是相对应的那个了。
在代码优化环节,例如减少文件下载次数,提供人机交互来手动输入sitemap地址,而不是每次编辑源代码等等。
在bug修复环节,例如使用本地缓存资源时,由于没有对sitemap进行分类、命名,导致两个不同的网站使用了同一个本地缓存的sitemap文件。
- 详细描述需求:在与AI交流时,详细描述每个功能点非常重要。最初,只是简单描述了需求,导致生成的代码功能不全。后来,逐条描述了每个步骤,AI生成的代码逐渐完善。
- 逐步优化:代码生成后,发现了许多可以优化的地方,如增加缓存机制、添加用户输入功能等。通过逐步提出优化建议,AI迅速进行了调整。
- 调试信息:在代码中加入调试信息可以帮助快速定位问题。虽然最终这些调试信息会被注释掉,但在开发过程中非常有用。
- 处理异常情况:在实际运行中,可能会遇到各种异常情况,如文件下载失败、解析错误等。在与AI交流时,特别强调了这些异常处理,确保代码的健壮性。
- 用户交互:为了提高用户体验,增加了用户输入功能,允许用户指定Sitemap索引URL,并设置了超时时间。这使得脚本更加灵活和实用。
在这次生成代码的过程中,深刻体会到了人工智能的强大和高效。通过与AI的互动,能够在短时间内生成一个功能完善的脚本,而不需要从头学习复杂的编程知识。AI不仅能够快速理解需求,还能根据反馈进行不断的优化和调整。这种高效的协作方式极大地提高了工作效率,让有更多时间专注于其他重要的任务。
问题复盘
在这次生成代码的过程中,也发现了一些与AI沟通不到位的问题,这些问题导致了代码的多次迭代和优化。以下是一些具体的例子和解决建议:
- 需求描述不够详细:最初,只是简单描述了需求,导致生成的代码功能不全。建议在描述需求时,尽量详细地列出每个功能点,确保AI能够准确理解需求。
- 缺乏异常处理的描述:在最初的交流中,没有提到需要处理异常情况,如文件下载失败、解析错误等。建议在描述需求时,明确指出需要处理的异常情况,以便AI生成更加健壮的代码。
- 优化建议不够具体:在提出优化建议时,有时描述得不够具体,导致AI无法完全理解意图。建议在提出优化建议时,尽量具体地描述希望达到的效果,例如增加缓存机制的具体实现方式。
- 调试信息的重要性:在开发过程中,调试信息对于快速定位问题非常有用。建议在与AI交流时,明确指出需要加入调试信息,以便在后续优化中更容易发现问题。
通过这次经历,不仅学会了如何更好地与AI交流,还深刻体会到了AI在编程领域的巨大潜力。希望这次分享能帮助更多像这样普通的用户,更好地利用AI工具解决实际问题。
事实上,本文也是借助AI生成的,而后又进行了编辑。
经过上述案例,在第二次生成代码的时候很明显就快捷了很多,也少了多次出现BUG、代码迭代。
第二次的代码与上面的类似,只不过将找到最新的URL替换为找一个随机URL,在sitemap文件中随机提取一条url。并且也要有一些优化,例如使用本地的缓存、减少下载次数等等。
最终的两段代码都上传到了Github,欢迎查阅。
https://github.com/babydu/get_latest_post/