从爬虫到面试题:一个小程序开发者的探索与优化之路

清醒开发者
2025-12-24 13:06
阅读 225

上周五晚上十点半,我还在公司调一个诡异的白屏问题。VSCode里插件装得比头发还多,但就是搞不定用户反馈的“页面偶尔打不开”。刚入职这家新公司两个月,业务压力不小,团队氛围倒是挺好——虽然产品经理又在群里@我说“这个需求很简单,明天上线吧”。

说来惭愧,我在腾讯做了三年微信小程序客户端开发,天天和 wx.request、本地缓存、分包加载打交道,自以为对前端性能优化已经炉火纯青。结果一跳槽,发现外面的世界早就卷到AI+数据驱动了。为了不被淘汰,我最近开始疯狂补课,啃书、刷LeetCode、甚至翻墙看国外技术博客。

而这一切的起点,竟然是一个看起来平平无奇的需求:我们需要从第三方网站抓取一些公开的图书信息,用于推荐系统冷启动。

没错,就是——爬虫。


起因:不是我想写爬虫,是业务逼的

事情是这样的。我们新做的一个阅读类小程序,需要初期有一些书籍数据填充首页。但合作方的API还没对接完,PM急得像热锅上的蚂蚁:“能不能先搞点数据?随便什么书都行!”

我一开始想:这不有现成的豆瓣API吗?结果一查,人家早就不开放免费接口了。GitHub上搜了一圈,发现不少开源项目用的是“模拟请求 + 正则匹配”那一套。行吧,既然躲不过,那就上。

但作为一个曾经在微信生态里被各种安全策略、域名白名单、HTTPS强制要求“调教”过的老客户端,我深知直接在小程序端做网络抓取是不可能的——不仅会被拦截,还可能被封号。所以方案很明确:后端写爬虫,前端只负责展示。

可问题是,我们后端人手紧张,排期排到下个月。领导看了我一眼:“你不是会Node.js吗?要不你先搭个临时服务?”

于是,我的“技术探索与实践优化”之旅,就这么开始了。


第一阶段:糙快猛的脚本式爬虫

我翻出大学时看的《Python网络数据采集》(Web Scraping with Python),虽然现在主力语言是JavaScript,但Python写爬虫确实香。装了个requests + BeautifulSoup,二十行代码就跑通了:

import requests
from bs4 import BeautifulSoup

url = "https://book.douban.com/tag/小说"
res = requests.get(url, headers={'User-Agent': 'Mozilla/5.0...'})
soup = BeautifulSoup(res.text, 'html.parser')
books = soup.select('.subject-item h2 a')
for book in books:
    print(book.get('title'), book.get('href'))

跑起来没问题,数据也拿到了。但当我试着并发抓100本书详情页时,IP直接被豆瓣封了。而且速度慢得像蜗牛——一页3秒,100页就是5分钟。

更麻烦的是,有些字段(比如评分、评论数)藏在动态加载的JS里,静态HTML根本拿不到。这时候我意识到:现代网站反爬机制早已不是十年前那样简单了。


转向Puppeteer:用浏览器模拟人类

既然静态解析不行,那就上无头浏览器!我切换到Node.js环境,用上了Puppeteer——这玩意儿我在微信小程序自动化测试时就玩过,熟悉得很。

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https https://book.douban.com/subject/123456/', {
    waitUntil: 'networkidle2'
  });
  const title = await page.$eval('#wrapper h1 span', el => el.textContent);
  console.log(title);
  await browser.close();
})();

效果立竿见影!动态内容全都能拿到,还能自动处理Cookie、登录态(虽然这次用不上)。但代价也很明显:资源消耗巨大。每次启动Chrome实例都要吃掉几百MB内存,CPU飙到80%。在我那台MacBook Air上跑三个并发就卡成幻灯片。

这时我想起以前在腾讯做压测时的经验:不要在生产环境直接跑重型爬虫。于是赶紧加了队列和限流:

  • 使用bull做任务队列
  • 每个任务间隔1.5秒
  • 同一域名最多2个并发
  • 自动轮换User-Agent和代理IP(用了免费的proxy池)

虽然还是慢,但至少不会被封,也不会把服务器干趴。


性能瓶颈:如何让爬虫快而不死?

随着数据量增大(目标是10万+书籍),效率成了最大问题。我开始思考优化路径:

  1. 能不能复用浏览器实例?
    答案是可以!Puppeteer支持page复用,避免频繁启停Chromium。我把核心逻辑改成了“一个浏览器,多个页面轮流使用”,内存占用降了40%。

  2. 能不能缓存已抓取页面?
    当然。我用Redis存了URL哈希值,重复请求直接返回缓存。顺便加了个TTL=7天,避免数据过期。

  3. 能不能分布式?
    想了想,暂时没必要。10万条数据,按每秒2条算,也就14小时。我们又不是做商业爬虫,够用就行。

最终,我整理了一份性能对比表:

方案 单页耗时 并发上限 内存占用 反爬绕过能力
requests + BS4 0.8s 10+
Puppeteer(单实例) 3.2s 1-2
Puppeteer(复用+队列) 2.1s 5
Playwright(尝鲜版) 1.9s 6 中高 极强

注:Playwright是微软出的,比Puppeteer更新,支持多浏览器,但我怕稳定性不够,没敢上生产。


顺手整理:那些年踩过的“爬虫面试题”坑

有意思的是,在折腾爬虫的过程中,我突然意识到:很多大厂面试题,其实就藏在这些实战细节里

比如前几天刷LeetCode,看到一道题:“如何设计一个高可用的分布式爬虫系统?” 我以前觉得这是纸上谈兵,现在才明白,这题考的就是你对调度、去重、容错、反爬、存储的理解。

我还特意翻了《剑指Offer》和《程序员面试金典》,发现至少有5道题和爬虫相关:

  • 如何检测网页是否更新?(ETag / Last-Modified)
  • 如何避免重复抓取?(Bloom Filter vs 哈希表)
  • 如何处理动态渲染内容?(SSR vs CSR识别)
  • 如何应对验证码?(打码平台 or 放弃)
  • 如何保证数据一致性?(事务 or 幂等)

甚至有一次小组分享,实习生问我:“哥,爬虫合法吗?” 我愣了一下,认真回答:“技术无罪,但使用有界。公开数据、遵守robots.txt、控制频率、不用于商业牟利——这是底线。”


回归前端:爬虫数据如何赋能小程序?

别忘了,我的本职工作还是小程序客户端开发。爬来的数据最终要展示给用户看。

于是我又开始折腾前端优化:

  • <scroll-view>实现虚拟滚动,10万条数据也不卡
  • 图片懒加载 + WebP格式,首屏快了40%
  • 本地缓存热门书籍,减少网络请求
  • 分包加载详情页,主包体积压到1.8MB以内

最骚的操作是:我把爬虫日志接入了小程序埋点系统。当用户点击某本书时,我会记录“该书是否来自爬虫源”,后续用来评估数据质量。产品经理看到报表后惊了:“你们还能追踪数据血缘?”


心得:技术探索的本质是解决问题

说实话,这次经历让我重新理解了“技术探索”的意义。
我不是为了炫技去写爬虫,而是因为业务卡住了,必须有人往前推一步

在腾讯那三年,我们总说“一切以用户价值为依归”。现在我才懂,工程师的价值,就是在约束条件下找到最优解——无论是性能、成本、合规,还是时间。

我也终于明白为什么那么多面试官爱问爬虫题。它不只是考你会不会写代码,而是看你:

  • 能不能权衡利弊(用简单方案 vs 复杂方案)
  • 有没有工程思维(日志、监控、回滚)
  • 是否尊重规则(法律、道德、技术边界)

最后:推荐几本对我帮助很大的书

如果你也想系统学习这类“跨界”技能,这几本书值得一看:

书名 适合场景 我的评价
《Web Scraping with Python》 入门爬虫 老但经典,讲透原理
《高性能MySQL》 数据存储优化 爬虫数据怎么存?看这本
《你不知道的JavaScript》 JS底层 写Puppeteer脚本必备
《算法导论》 面试题攻坚 Bloom Filter在哪章?第11章!
《微信小程序开发实战》 本职工作 别笑,真有人没看过官方文档

现在,那个临时爬虫服务已经稳定运行三周,每天凌晨自动增量抓取,数据准确率98%以上。上周产品会上,PM居然说:“要不把这个做成后台通用能力?” —— 我表面微笑,心里OS:又要加需求了?

但转念一想,这也说明技术真的创造了价值。
从一行爬虫脚本,到支撑业务增长的数据管道,再到面试时能侃侃而谈的实战案例——这就是我们普通程序员的“小确幸”吧。

对了,如果你也在学AI,不妨试试用LLM分析爬取的书籍评论情感倾向。我刚跑通了一个demo,准确率还挺高…… 这又是另一个故事了。

(完)

作者:前腾讯小程序客户端开发,现某创业公司全栈打杂选手。日常用VSCode写代码,插件列表比购物车还长。最近在研究如何用AI自动修复线上Bug——虽然目前只会让它帮我写周报。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝