过年回家,是合家欢聚的热闹时刻。可我的外甥,放假依然在家“葛优躺”
不是打游戏就是看动漫,什么学习?通通抛到九霄云外。
看得我这个沉迷AI编程的舅舅,脑袋都快冒烟了!你说将来谁给我端碗饭呀?没辙,我只能使出杀手锏——自己写个小爬虫,抓一堆卷子回来让他“开卷有益”!
话不多说,一切为了年后的“少儿不宜”——我外甥的快乐寒假,现在马上进入正题!
一、脑洞大开:我要写个小爬虫
我先跟我的得力 AI 伙伴——Cursor 商量了一下需求:
1.我需要一个爬虫脚本,从某个试卷网站批量下载试卷。
2.下载的文件还是 .rar 压缩包,解压后只需要其中的 .doc 文件。
3.最好支持多线程下载,以便能在我家网速还行的时候迅速搞定。
4.最后自动把 .rar 删了,省得占地方。
5.没啥特别复杂的容错需求,但也要跑得稳。
Cursor 秒回我一个“稳得一匹”的多线程爬虫思路,而且还贴心地给了下载、解压、删除一条龙服务的示例。完美,我先在本地跑起来看看!
二、搬砖现场:我的爬虫代码 Cursor 给出的思路非常清晰,我又稍微改动了一下(主要是加了点自己的注释和打印语句,毕竟我得知道下载到哪了),然后就得到了下面这段终极解决方案:
import concurrent.futures
import os
import threading
from concurrent.futures import ThreadPoolExecutor
import rarfile
import requests
from bs4 import BeautifulSoup
def download(url, category, level, name):
path = category + "/" + level + "/" + name + ".rar"
dir_name = os.path.dirname(path)
os.makedirs(dir_name, exist_ok=True)
res = requests.get(domain + url, headers=dic)
with open(path, "wb") as f:
f.write(res.content)
f.flush()
print(f'线程:{threading.current_thread().name} 下载完成:{path}')
# 解压
extract_rar(path, category + "/" + level)
# 自动删除rar
os.remove(path)
def extract_rar(file_path, extract_path):
with rarfile.RarFile(file_path) as rf:
for member in rf.infolist():
if not member.filename.endswith('.doc'):
continue
rf.extract(member.filename, extract_path)
def getPageList(page_index):
page_url = f"a/sjyw4/list_109_{page_index}.html"
root = requests.get(domain + page_url, headers=dic)
root.encoding = "gb2312"
root_html = BeautifulSoup(root.text, "html.parser")
tr_list = root_html.find("div", class_="listbox").find("table").find_all("tr")
for index, tr in enumerate(tr_list):
if index == 0 or (tr.text.find(".doc") == -1):
continue
tds = tr.find_all("td")
name = tds[0].text
suffix = tds[1].text
level = tds[2].text
category = tds[3].text
child_url = domain + tds[0].find("a").get("href")
child_html = BeautifulSoup(requests.get(child_url, headers=dic).text, "html.parser")
a = child_html.find("div", class_="content").find_next("a")
down_url = a.get("href")
print(f'开始下载:{category}-{level}-{name}{suffix} url: {domain}{down_url}')
task = pool.submit(download, down_url, category, level, name)
task_list.append(task)
if __name__ == '__main__':
domain = "https://www.shijuan1.com/"
dic = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:68.0) Gecko/20100101 Firefox/68.0"
}
# 创建线程池
pool = ThreadPoolExecutor(5)
task_list = []
# 遍历10页,下载
for page in range(1, 10):
getPageList(page)
# 等待所有任务完成
concurrent.futures.wait(task_list, return_when='ALL_COMPLETED')
pool.shutdown()
print("所有任务完成,共下载{}个文件", len(task_list))
代码亮点
1.多线程下载:
ThreadPoolExecutor(5) 预设了 5 个线程,让下载像子弹一样飞快。
2.RAR 解压 + 清理:
写完一个 extract_rar() 就把 .rar 解压,再把多余的压缩包删干净。
3.批量爬:
for page in range(1, 10): 我这里选了 1~9 页,总共要批量下载。
三、与 Cursor 的斗智斗勇:代码优化过程
我最初是打算写一堆 requests 请求再手动解压,但 Cursor 一语点醒梦中人:“请用多线程与自动解压!”
我之前用 Python 自带的 zipfile,结果发现我下到的是 .rar 格式文件,Cursor 贴心地提醒说:“你可以用 pip install rarfile 嘛。”
然后又顺带安利我 ThreadPoolExecutor,让整个下载效率直接飞起。
整个过程可谓火花四溅,Cursor 不仅安抚了我的懒癌,还帮我排查了编码问题,比如网站的 root.encoding = "gb2312",非常中国特色。要是没这行,怕是中文会变成火星文吧!
四、实践出真知:再买个打印机!
搞定代码后,我立刻:
1.买了一台打印机 2.下载了100套试卷 3.打印装订好
准备在大年初一的时候,亲手交给我亲爱的外甥。毕竟谁说程序员就不会关心教育下一代呢?只是我们的方式...可能比较特别😏
五、总结
编程真的离不开AI助手了。Cursor不仅帮我生成代码,还能智能优化、提供建议
多线程果然是提升效率的利器,下载速度提升了好几倍
最重要的是 - 我终于有"教育资源"了
过年嘛,干活和快乐都要两手抓!希望大家看到这里,能体会到我这位苦口婆心的舅舅的良苦用心……
好了,撒花!祝大家新年快乐!记得早点写好爬虫,让你家孩子也能随时开卷!
PS: 各位读者朋友如果也想要这个代码,可以在评论区留言。不过我建议谨慎使用,毕竟...过年还是要让孩子们适当放松的嘛!