搜索引擎会根据特定的策略,运用特定的计算机程序搜集互联网上的公开信息,再对收集到的信息进行组织和处理后展示给用户,而这些经过处理后公开展示的数据就是搜索引擎结果数据即SERP(Search Engine Results Page)。我们所说的搜索引擎爬虫,其实就是基于搜索引擎已经处理过的SERP数据的二次收集,以用于特定业务的分析。
1.搜索引擎爬虫突出的两个问题:
● 主流搜索引擎都有严格的风控策略,如Google验证码,解决难度极高,技术上需要特殊处理
● 会拒绝访问密集的请求,技术上需要特殊处理,同时需要大量IP池资源
2.传统搜索引擎采集的方案:
传统的爬虫方案是使用不同地区的IP构建代理IP池或者购买第三方代理IP池,然后开发主流搜索引擎采集程序调用代理IP池进行采集,大规模采集的话需要定制化开发处理平台的风控策略,如封IP、指纹识别、验证码等。当然优点是简单直接、成本低、可定制化爬虫需求,适合小规模、简单数据分析场景。
但是在规模化爬虫场景下弊端也非常明显:
● 工作量大,搜索引擎众多且每个搜索引擎有多个板块,每个板块都需要开发采集程序,写大量解析规则
● 自建IP池或者低质量代理IP,稳定性和数量不能很好保障,在反爬虫机制下IP资源会持续消耗,从而影响速度和数据的准确性
● 需要高级工程师开发相关风控模块,主流搜索引擎都有严格的风控策略,如Google验证码,解决难度极高
3.亮数据 Bright Data SERP采集方案
最近SERP数据采集使用的是亮数据Bright Data研发的针对搜索引擎的采集产品,功能和亮点总结如下:
● 支持采集市面上主流的搜索引擎数据:Google、Bing、Yandex、DuckDuckGo等
● 上手方便,可自定义搜索参数,如页码、语言、定位、搜索类型等
● 支持搜索引擎常用板块的自动解析,无需编写大量采集程序和解析规则,支持采集不同板块的数据,如:关键字搜索、图片、购物、新闻、酒店、视频等
● 集成亮数据Bright Data全球网络代理,无需单独购买IP(就速度和结果来看,号称超7200万合法合规IP覆盖195个国家还是名副其实的)
● 集成自家研发的解锁技术,可以解决搜索引擎风控问题,摆脱网站反爬取限制,无需单独编写反爬虫程序模块
缺点:
● 采集成本相比传统代理较高(个人爬着玩的就不划算了)
● 产品普适性高,受限于产品的解析模板,复杂型定制化采集建议使用Web Scraper IDE(也是他家的产品)
此产品的开发目标是快速便捷大规模采集搜索引擎网页数据并与自家其他产品进行集成,对于定制化程度较高较复杂的产品,建议使用亮数据Bright Data 数据采集器(Web Scraper IDE)进行自定义采集,这个是通过低代码框架定制化开发,不需要考虑服务器基础设施、代理IP池,上手快,和SERP的解锁能力一样。简言之,相较于传统搜索引擎采集方案,亮数据Bright Data的SERP产品更为智能,可以便捷高效的获取搜索引擎数据,虽然成本比传统代理高,但人工成本和时间成本却大大降低了。有大规模采集需求的推荐一试。
4.亮数据Bright Data SERP工作原理
● 客户端程序将搜索的url传给SERP API
● SERP系统根据传入的url,自动识别请求的搜索引擎,并通过代理、解锁器等技术解析和获取目标搜索引擎页面的数据
● SERP系统将解析好的数据以HTML/JSON格式传回给客户端
从获取数据的整个过程可以看出,客户端只关心获取哪些业务数据,无需操心任何风控,全权交由亮数据Bright Data智能系统解决,极为方便。
5.亮数据Bright Data SERP基本使用
注册Bright Data账号直接官网登录,不需要下载。在控制面板代理通道创建搜索引擎爬虫通道,添加IP白名单,之后就可以指令模拟。(很简单,上去大概看一下就能明白)
在指令模拟页面我们可以很方便的进行SERP API调试,获取我们需要的API参数和效果预览。可以看到当我们设置参数时,底下会自动生成多种语言的API代码,还可以尝试请求获取实时数据,方便我们将SERP API集成到我们的应用程序。
6.亮数据Bright Data SERP采集测试
接下来我将用一个采集案例来展示SERP完整的使用过程以及如何将SERP API集成到我们的采集程序。该案例是:使用Python Scrapy集成SERP API采集Google购物板块电商商品数据,并将json数据存入mongodb。
1.SERP API调试
还是在指令模拟页面调试API,获取我们需要的目标API。
搜索引擎选择Google,且搜索类型选择购物:
这里我们设定的关键字是pizza,也就是采集指定条件的pizza相关数据。
定位选择香港(可根据自己需求选择):
指定API通道和返回数据格式:
当设置好后会自动生成API代码,而且我们可以点击关键字搜索按钮看下结果预览:
从自动生成的API代码中提取几个关键参数记录下来,一会代码中要用:PROXY_URL、PROXY_USER、PROXY_PASSWORD、URL。如图所示:
2.代码目录结构
brightdata/
├── brightdata
│ ├── __init__.py
│ ├── middlewares.py
│ ├── pipelines.py
│ ├── settings.py
│ └── spiders
│ ├── __init__.py
│ └── serp_spider.py
└── scrapy.cfg
主要文件:
● brightdata.spiders.serp_spider.py:搜索引擎Spider类
● brightdata.middlewares.py:中间件,包含代理中间件类
● brightdata.pipelines.py:存储管道,包含mongodb存储管道类
3.Spider类编写
serp_spider.py:
class SerpSpider(scrapy.Spider):
# Spider名称
name = 'serp'
# 配置
custom_settings = {
# 代理配置
'PROXY_URL': 'http://zproxy.lum-superproxy.io:22225',
'PROXY_USER': 'xxxxxx',
'PROXY_PASSWORD': 'xxxxxx',
'DOWNLOADER_MIDDLEWARES': {
'brightdata.middlewares.BrightProxyMiddleware': 350
},
# mongodb存储管道配置
'ITEM_PIPELINES': {'brightdata.pipelines.MongoPipeline': 300},
'MONGO_URI': 'mongodb://127.0.0.1:27017',
'MONGO_DATABASE': 'Test',
'MONGO_COLLECTION': 'serp_results'
}
# 最大页数
max_pages_count = 10
def start_requests(self):
urls = [
# 这是我们在指令模拟页面调试好的目标URL,这块可以添加多个或者从任务队列获取
'https://www.google.com/search?q=pizza&tbm=shop&location=Hong+Kong&uule=w+CAIQICIJSG9uZyBLb25n&lum_json=1',
]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
def parse(self, response):
response_json = json.loads(response.text)
yield response_json
# 翻页
pagination = response_json['pagination']
if pagination.get('current_page') and pagination['current_page'] < self.max_pages_count:
next_page_link = response_json['pagination']['next_page_link'] + "&lum_json=1"
yield scrapy.Request(next_page_link, callback=self.parse)
Spider类:
● custom_settings为Spider配置,主要指定了中间件和存储管道,该配置优先级高于settings.py里的配置
● start_requests方法用来生产请求,就是我们要采集的搜索引擎请求
● parse方法用来解析响应数据以及进行翻页请求
4.代理中间件编写
middlewares.py:
class BrightProxyMiddleware(object):
download_timeout = 60
@classmethod
def from_crawler(cls, crawler):
return cls(crawler.settings)
def __init__(self, settings):
self.proxy_url = settings.get('PROXY_URL')
self.proxy_user = settings.get('PROXY_USER')
self.proxy_pass = settings.get('PROXY_PASSWORD')
def process_request(self, request, spider):
request.meta['proxy'] = self.proxy_url
request.headers['Proxy-Authorization'] = basic_auth_header(self.proxy_user, self.proxy_pass)
request.meta['download_timeout'] = self.download_timeout
代理中间件类:
● 构造函数中会从配置文件中获取代理配置
● process_request方法会在每次请求前在请求meta中添加代理信息,这样请求时就会使用Bright Data的代理进行访问
5.mongodb存储管道编写
pipelines.py:
class MongoPipeline(object):
def __init__(self, mongo_uri, mongo_db, mongo_col):
self.mongo_uri = mongo_uri
self.mongo_db = mongo_db
self.mongo_col = mongo_col
@classmethod
def from_crawler(cls, crawler):
return cls(
mongo_uri=crawler.settings.get('MONGO_URI'),
mongo_db=crawler.settings.get('MONGO_DATABASE'),
mongo_col=crawler.settings.get('MONGO_COLLECTION')
)
def open_spider(self, spider):
self.client = pymongo.MongoClient(self.mongo_uri)
self.db = self.client[self.mongo_db]
def close_spider(self, spider):
self.client.close()
def process_item(self, item, spider):
self.db[self.mongo_col].insert_one(ItemAdapter(item).asdict())
return item
mongodb存储管道类:
● 构造函数中会从配置文件中获取mongo配置
● open_spider方法会在Spider启动时创建mongo client和db
● process_item方法会将Spider yield的item存储到mongodb
6.运行程序
运行环境:
● 操作系统:Ubuntu 20.04
● Python版本:3.8
● Python第三方依赖:
o Scrapy==2.7.1
o pymongo==4.3.3
● mongodb版本:6.0.3
运行:
$ cd bright
$ scrapy crawl serp
结果:
查看mongodb中采集下来的数据
通过此案例可以了解SERP API如何使用以及如何集成到我们的采集程序,可以看到使用过程中我们完全不需要关心如何解决验证码、封IP的问题,而且也不需要我们编写繁琐的页面解析规则,只要调用代理中间件,交由SERP API即可。
7.总结
如本文章所述,总结对比两个方案如下:
传统方案 | 亮数据Bright Data SERP API | |
---|---|---|
集成方式 | IP即服务方式,提供IP | 数据即服务方式,提供数据 |
封控处理 | 需要自行开发处理IP封控,指纹,验证码 | API 内置封控处理,用户无感 |
服务稳定性 | IP池不可控,稳定性差 | 全球大量IP池,稳定性高 |
开发集成工作量 | 适配不同搜索引擎,处理封控 | 适配主流搜索引擎,内置封控处理 |
成本 | IP成本较低,人工和时间成本较高 | IP成本较高,综合人工和时间成本低 |
个人心得:爬虫和反爬虫的游戏永远不会停止,只要是互联网公开信息,就有被爬取的可能。但是个人观察,针对规模化采集的需求,随着主流搜索引擎的反爬虫技术的发展,综合成本以及合规性方面的考虑,越来越多的公司会倾向于寻找第三方符合资质的技术公司提供产品/服务而非自建技术团队或者外包技术团队采集数据。