公司动态
不用学正则!3行代码爬取猫眼电影TOP100,新手也能搞定文本保存
摘要还在为正则表达式的贪婪匹配、回溯陷阱头疼本文带你跳出“正则崇拜”用requestsparselpandas三件套以极简代码完成猫眼电影TOP100的抓取与持久化。文章不仅给出可直接运行的代码还深入剖析了“为什么不用正则”的工程思维并附上完整流程图与反爬避坑指南。适合爬虫入门者、数据分析新手及希望提升代码可维护性的开发者阅读。一、 为什么我劝你别在入门阶段死磕正则在CSDN搜“猫眼TOP100爬虫”90%的文章都在教你写正则。诚然正则是基本功但在实际工程中它往往是最脆弱的一环。1.1 正则的三大“劝退”痛点痛点说明对新手的影响可读性差.*?board-index.*?(\d)这种表达式一周后自己都不认识维护成本极高结构敏感HTML标签换个顺序、加个class正则直接失效调试时间远超开发时间缺乏语义正则只认字符模式不认DOM树无法处理嵌套、属性动态变化1.2 更好的选择CSS/XPath选择器 结构化存储现代爬虫的最佳实践是“解析归解析存储归存储”解析层用parselScrapy同款或BeautifulSoup通过CSS选择器定位节点像操作DOM一样提取数据。存储层用pandas一行代码写入CSV/Excel/TXT告别手动拼接字符串和文件IO异常处理。核心观点“3行代码”不是噱头而是技术选型正确后的自然结果。当你把脏活累活交给专业库业务逻辑自然就只剩几行。二、 整体架构与流程设计在动手写代码前先理清数据流转过程。下面是本次爬虫的完整流程图否是开始构造URL列表offset0,10,...,90requests.get 获取HTML状态码200?记录错误日志跳过当前页parsel.Selector 解析HTMLCSS选择器提取排名/片名/主演/时间/评分数据清洗与结构化pandas.DataFrame 汇总to_csv 保存为文本文件结束关键设计决策说明分页策略猫眼TOP100每页10条offset参数从0到90步长10共10页。解析方案使用CSS选择器而非XPath因为猫眼页面结构扁平CSS更简洁。存储方案pandas.to_csv()自带编码处理、表头生成、分隔符控制完美替代手写文件写入。容错机制单页失败不影响整体避免“爬了90页在第91页崩溃”的悲剧。三、 环境准备与依赖安装pipinstallrequests parsel pandas⚠️注意parsel是Scrapy团队出品的独立解析库比BeautifulSoup快5-10倍且支持CSSXPath双语法。如果你后续想学Scrapy现在用它零迁移成本。四、 核心代码实现含逐行深度注释4.1 真正的“3行核心”长这样importrequestsfromparselimportSelectorimportpandasaspd# 以下为核心逻辑其余都是工程化包装 htmlrequests.get(url,headersheaders).text# 第1行获取rowsSelector(html).css(dd).getall()# 第2行解析dfpd.DataFrame([parse_item(r)forrinrows])# 第3行结构化# 当然生产级代码不能只有3行。下面是完整可运行版本4.2 完整代码importtimeimportrandomimportrequestsfromparselimportSelectorimportpandasaspd HEADERS{User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36,Referer:https://maoyan.com/board/4}deffetch_page(url:str)-str|None:安全地获取单页HTMLtry:resprequests.get(url,headersHEADERS,timeout10)resp.raise_for_status()returnresp.textexceptrequests.RequestExceptionase:print(f[ERROR]{url}{e})returnNonedefparse_items(html:str)-list[dict]:用CSS选择器提取一页中的所有电影条目selSelector(html)items[]forddinsel.css(dd):item{rank:dd.css(.board-index::text).get().strip(),title:dd.css(.name a::text).get().strip(),star:dd.css(.star::text).get().strip().replace(主演,),releasetime:dd.css(.releasetime::text).get().strip().replace(上映时间,),score:.join(dd.css(.score i::text).getall()).strip(),}# 过滤掉空数据防止页面结构微调导致脏数据ifitem[title]:items.append(item)returnitemsdefmain():base_urlhttps://maoyan.com/board/4?offset{}all_items[]foroffsetinrange(0,100,10):urlbase_url.format(offset)print(f 正在抓取: offset{offset})htmlfetch_page(url)ifhtmlisNone:continueitemsparse_items(html)all_items.extend(items)print(f ✅ 本页获取{len(items)}条)# 随机休眠1~3秒尊重服务器time.sleep(random.uniform(1,3))# 3行代码的高光时刻 dfpd.DataFrame(all_items)df.to_csv(maoyan_top100.csv,indexFalse,encodingutf-8-sig)print(f\n 完成共{len(df)}条数据已保存至 maoyan_top100.csv)# if__name____main__:main()4.3 代码深度解读为什么用utf-8-sig而不是utf-8这是CSDN上无数人踩过的坑用Excel打开UTF-8 CSV时中文乱码。utf-8-sig会在文件头写入BOM标记Excel能正确识别编码。这一个参数省去了你90%的“保存成功但打开乱码”问题。为什么用.get()而不是.get().get()在节点不存在时返回None后续调用.strip()会抛AttributeError。.get()提供默认空字符串让链式调用永远安全。防御性编程比事后try-except更优雅。为什么不用多线程对于10页、总量100条的轻量任务多线程带来的复杂度线程安全、速率控制、异常传播远大于收益。简单任务用简单方案这才是工程素养。当数据量上千时再考虑并发不迟。五、 运行效果与数据验证运行上述代码后控制台输出如下 正在抓取: offset0 ✅ 本页获取 10 条 正在抓取: offset10 ✅ 本页获取 10 条 ... 完成共 100 条数据已保存至 maoyan_top100.csv生成的CSV文件内容预览ranktitlestarreleasetimescore1霸王别姬张国荣,张丰毅,巩俐1993-01-019.52肖申克的救赎蒂姆·罗宾斯,摩根·弗里曼1994-09-109.53泰坦尼克号莱昂纳多·迪卡普里奥,凯特·温丝莱特1998-04-039.4验证技巧拿到数据后先用df.info()检查字段类型和非空计数再用df.head()肉眼校验前几条。不要等到分析阶段才发现数据缺失。六、 进阶思考从“能跑”到“能用”6.1 如果猫眼改版了怎么办CSS选择器的优势在此刻体现你只需要修改parse_items函数中的选择器字符串其他所有代码请求、存储、调度完全不用动。而正则方案可能需要重写整个匹配模式。6.2 如果想存到数据库pandas同样一行搞定fromsqlalchemyimportcreate_engine enginecreate_engine(mysqlpymysql://user:passlocalhost/movie_db)df.to_sql(maoyan_top100,engine,if_existsreplace,indexFalse)同一份DataFrame换一种输出方式就是换一行代码的事。这就是结构化数据的威力。6.3 合规与伦理提醒原则具体做法遵守robots.txt访问https://maoyan.com/robots.txt确认允许路径控制频率单次请求间隔≥1秒总QPS≤1数据用途仅用于学习研究不商用、不二次分发缓存优先开发调试时先保存HTML到本地反复解析本地文件七、 总结技术选型的本质是权衡回到标题“3行代码”的本质不是炫技而是传达一个理念好的代码不是写得少而是把复杂性转移到了正确的地方。把解析复杂性转移给parsel专业解析器把存储复杂性转移给pandas专业数据工具把网络复杂性转移给requests专业HTTP库你的业务代码自然就只剩下“获取→解析→存储”这三步。下次再遇到类似的结构化数据抓取需求请先问自己“这个问题真的需要正则吗”大多数时候答案是否定的。参考资料parsel官方文档pandas.to_csv参数详解Python爬虫合规指南2025版免责声明本文代码仅供学习交流请严格遵守目标网站的使用条款和相关法律法规。作者不对任何因使用本文代码而产生的法律后果负责。如果这篇文章帮你省下了学正则的时间不妨点个赞收藏一下。有问题欢迎评论区交流我会逐一回复。