爬虫技术抓取网站数据软件

写爬虫的爬虫人,十个有九个是技术从“抓豆瓣电影Top250”开始的。我也不例外。网站2016年那会儿,数据我写了不到五十行Python,软件用requests加BeautifulSoup,爬虫十分钟就把榜单拽了下来。技术当时觉得这事儿太简单了,网站网页不就是数据一堆标签吗?找到规律,循环提取,软件完事。爬虫

后来接了个活,技术要抓某电商平台的网站商品价格。网站用的数据是React,页面源码里干干净净,软件价格数据全是JavaScript动态渲染出来的。requests拿到的HTML里根本没有数字。那一刻我才明白,爬虫和反爬之间,隔着的不只是技术,是耐心。

静态页面:入门者的舒适区

静态网页抓取确实没什么门槛。服务器把完整HTML吐回来,你只管解析。requests负责拿,lxml或BeautifulSoup负责拆。遇到分页,观察URL规律,改个参数循环就行。比如很多新闻站,列表页是/list?page=1这种结构,写个for循环,range(1, 51),每页sleep一秒,半小时能撸几万条标题。

但这里有个坑:编码。中文网站经常用GBK或者GB2312,requests默认按ISO-8859-1解码,结果就是一堆乱码。手动指定response.encoding = 'gbk'能解决大部分问题。还有,别小看robots.txt,有些站直接在里面写了Disallow: /,你硬抓,人家封IP没商量。

动态渲染:真正的战场

JavaScript渲染的页面,requests就废了。你得请出Selenium或者Playwright。Selenium控制真实浏览器,等页面加载完再取DOM。慢,但稳。Playwright更快,API也更现代,微软出品,支持异步。我现在的习惯是,能用Playwright就不用Selenium。

不过浏览器自动化资源消耗大。开一个Chrome实例,内存直接涨200M。抓几十个页面还行,上万个就得考虑分布式。而且很多网站检测webdriver特征,navigator.webdriver这个属性一暴露,直接给你弹验证码。得用CDP命令或者注入JS把特征抹掉。

接口逆向:效率最高的路子

大部分动态网站,数据其实是通过XHR或Fetch请求拿到的。打开开发者工具,切到Network面板,刷新页面,找那些返回JSON的请求。直接模拟这些接口,比渲染整个页面快十倍不止。

举个例子,某招聘网站职位列表,页面看着是动态加载的,实际上背后调的是/api/search?city=北京&page=2这种接口。你只要带上正确的headers和cookies,用requests直接请求接口,返回的就是结构化JSON。解析起来不要太舒服。

难点在于签名参数。很多接口会带一个sign或者_token,由前端JS生成。这时候要么用PyExecJS跑那段JS,要么用Playwright直接执行JS函数拿结果。前者快,后者省事。看情况选。

反爬与对抗:一场没有终点的游戏

IP封锁是最常见的。解决办法就那几种:代理池、请求间隔随机化、分布式部署。代理池质量参差不齐,免费的基本不能用,付费的也得测试。我一般用住宅代理,贵,但封得慢。

验证码更麻烦。简单的图形验证码可以用ddddocr,准确率还行。滑块验证码得用OpenCV算缺口距离,再模拟人类拖动轨迹。极验那种,直接上打码平台吧,省心。

还有行为检测。鼠标移动轨迹、点击频率、页面停留时间,这些都会被打点记录。Selenium默认的操作太机械,得加随机延迟和贝塞尔曲线鼠标移动。说白了,就是装得像个人。

数据落地:别只存CSV

新手喜欢存CSV,简单。但数据量一大,CSV就力不从心了。字段里带逗号、换行,解析起来全是坑。我一般直接写SQLite或者MySQL。MongoDB也行,JSON结构直接塞,不用建表。

去重是个细节。用URL的MD5做唯一索引,插入时用INSERT OR IGNORE,省得写一堆判断逻辑。增量抓取的时候,记录上次抓取的时间戳,下次只拿新数据。

爬虫这行,技术更新快,今天能用的方法明天可能就失效。保持学习,保持克制。别把人家网站抓崩了,也别拿数据干坏事。写代码之前,先想想边界在哪。