爬虫技术抓取网站数据百度网页
用Python写个爬虫抓百度搜索结果,爬虫这事我干过不下二十次。技术第一次跑通的网站网页时候,盯着终端里哗啦啦滚出来的数据标题和链接,确实爽。百度但很快你就会发现,爬虫百度不是技术吃素的。
最朴素的网站网页写法,requests.get('https://www.baidu.com/s?数据wd=关键词'),然后BeautifulSoup解析。百度跑一次两次没问题,爬虫跑上十次,技术页面就开始返回验证码了。网站网页百度对IP的数据请求频率卡得很死,同一IP连续快速请求,百度基本撑不过二十次。
我试过加time.sleep(random.uniform(1,3)),管用,但效率直线下降。抓一千个关键词,光等待就要大半个小时。后来换了代理池,免费代理基本不能用,十个里能有一个活着就算走运。付费代理质量参差不齐,有些号称高匿的,实际上早就被百度标记了。
请求头也是个坑。默认的User-Agent是python-requests/2.x,百度一眼就认出来。换成浏览器的UA只是第一步,还得加上Accept、Accept-Language、Referer这些。我习惯直接复制Chrome开发者工具里的一整套请求头,省事。但即便如此,百度还是会通过Cookie里的BAIDUID来追踪会话。你不带Cookie,它觉得你可疑;你带Cookie,它知道你是谁。两难。
解析这块,百度搜索结果页的HTML结构经常变。今天用div.result能抓到,明天可能就变成div.result-op。我一般用div[class*="result"]这种模糊匹配,稍微稳一点。标题通常在h3标签里,链接在h3 > a的href属性中。但百度的跳转链接是加密的,href拿到的是http://www.baidu.com/link?url=xxxxx这种,得再发一次请求才能拿到真实URL。这一来一回,又多了被检测的风险。
有个取巧的办法:用百度自己的移动端接口。比如https://m.baidu.com/s?word=关键词,返回的HTML更简单,反爬也松一些。我测过,同样的频率,PC端早被封了,移动端还能撑一阵。不过移动端的结果数量和PC端有差异,看你能不能接受。
再进阶一点,上Selenium或者Playwright。模拟真实浏览器操作,鼠标移动、滚动、点击都加上。百度对Selenium的检测主要看navigator.webdriver这个属性,用CDP改掉就行。但资源消耗大,开一个Chrome实例至少占几百兆内存,批量抓取时机器扛不住。我一般只在调试阶段用Selenium,跑通流程后换成requests加代理。
说个真实案例。去年帮朋友抓一批行业关键词的百度搜索结果,大概三千个词。第一版脚本用单IP加随机延时,跑了四百个词就被封了。换代理池后,代理质量不行,成功率不到六成。最后改成移动端接口加多线程,每个线程独立代理,延时控制在2到5秒,成功率拉到九成以上。但代价是跑了整整一个下午。
法律层面得提一句。百度robots.txt里明确写了Disallow: /s,意思就是别抓搜索结果页。你偷偷抓,百度一般懒得管个人小规模使用。但要是拿去商用,或者抓取量特别大,律师函不是闹着玩的。我自己的原则是:只抓公开数据,控制频率,不对外分发。
最后说个观察。百度这两年搜索结果页的广告越来越多,自然结果被挤到下面。你抓的时候得注意区分,广告的div通常带ec_ad或者result-op这类class。不滤掉的话,抓回来的数据里一半是推广链接。我一般用div[tpl]来定位自然结果,百度的自然结果基本都带这个属性。但也不是百分百准,得定期检查。
爬虫这东西,写起来不难,难的是稳定跑下去。百度的反爬策略一直在变,今天能用的方法,下个月可能就失效了。保持更新,别死守一套代码。
