背景介绍 公司在各电商平台(亚马逊/沃尔玛/Ebay/京东国际/速卖通)有大量商品,但是没有一个能聚合各商品的排行的工具或功能。现需开发一个每月统计商品排行的功能,供公司数据决策做参考。 对上述5个平台了解后发现只有亚马逊有提供精准排行数据,其他平台如必须则只能通过在指定商品分类的列表页去搜索该商品 才能得知排行,商量后觉得这种方式不可取,所以暂时只抓取亚马逊的排行数据,星级/评论数为附带抓取数据。 方案选择 F12查看内容发现数据是绑定到dom上的 没有直接的ajax数据接口可用(一般有直接的数据接口优选接口),所以只能取dom解析得到数据。
得到dom可用通过以下方案 (https://站点host/dp/asin)
方案一 jsoup(解释1)直接访问listing页面 优点:只访问单页 不加载静态资源(js/css/img…) 给代理省流量;速度快 缺点:如果对方服务器通过静态资源做页面事件监听并以此为风控鉴定(解释2),则很快会被限流或直接禁止访问 方案二 selenium(解释3)访问listing页面,并将dom转换为jsoup的dom(jsoup对dom解析的api更好用),然后解析数据
优点:基本可以直接忽略接口加密、页面行为上传的导致的风控
缺点:速度慢;打开一个链接附带的所有静态资源都会占用代理带宽 出现的问题及解决方案 问题一 验证码 先方案一在本地运行
一段时间后发现dom里没有相关数据了,debug发现http403直接跳转到了验证码页面,好在验证码都是比较简单的;jsoup不能直接操作dom,要破解验证码+发送验证码接口,这样比较麻烦,为了省时,直接使用方案二,将识别好的验证码通过webdriver发送过去。 解决方案
切换方案二 使用python的easyocr+flask 搭建了一个验证码识别服务;easyocr在linux下安装可能有点麻烦 按教程多试几次。easyocr验证码识别率做不到100%,但是整体还是可以接受的。
coding=utf-8
import base64 import urllib import uuid
from flask import Flask from flask import request, json import easyocr import os
app = Flask(name) reader = easyocr.Reader(['ch_sim', 'en'], gpu=False)
接口的入参是验证码图片的url
@app.route('/ocrUrl', methods=['POST']) def ocrCaptchaUrl(): try: data = request.get_data() print(data) json_data = json.loads(data.decode("UTF-8"), strict=False) allow = json_data.get("allow") url = json_data.get("url")
lua
体验AI代码助手
代码解读
复制代码
rsp = urllib.request.urlopen(url) file_name = str(uuid.uuid1()) + ".jpg" file = open(file_name, "wb") file.write(rsp.read()) file.close() res = reader.readtext(file_name, detail=0, allowlist=allow) os.remove(file_name) return '{"status":"200", "result":"' + res[0] + '"}' except Exception as e: print(e) return '{"status":"500"}'
ifname== 'main': app.run(host='0.0.0.0', port=8181)
AI写代码 python 运行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 问题二 代理带宽不够 linux下运行一段时间后 日志经常报错浏览器超时崩溃,经排查发现是代理带宽不够用,因为selenium加载一个链接时会加载附带的所有静态资源,对代理带宽消耗大。
解决方案
修改chromeDriver配置 不加载img/css等资源 // 禁用图片 & 样式 & flash Map prefs = new HashMap<>(); prefs.put("profile.managed_default_content_settings.images", 2); prefs.put("profile.managed_default_content_settings.stylesheet", 2); prefs.put("dom.ipc.plugins.enabled.libflashplayer.so", "false"); chromeOptions.setExperimentalOption("prefs", prefs); AI写代码 java 运行 1 2 3 4 5 6 linux服务器配置比本地机器高,访问速度快,控制selenium访问速度,单条记录最少3200毫秒 问题三 防止过快被服务器标记 一直在抓取,容易被标记ip导致长时间不能访问,这点是防范于未然。
解决方案
程序每开启一个chrome,都随机配置一个UserAgent,爬取n条记录后销毁chrome 下次需要再重新生成。 线程id和chrome绑定,控制并发 最多使用N(线程个数)个chrome实例。 代理和非代理轮番使用。因为代理资源不够,所以使用代理时效率低,但是又不能完全使用服务器ip去抓取,所以这里轮番去使用,且定时任务执行了10次后休息一段时间 问题四 其他业务细节问题以及平时粗心容易犯的错误就不记录了
解释 解释1:jsoup 爬虫工具库,主要包含http的请求操作、Dom解析操作。提供的dom api操作起来和jQuery一样非常方便
解释2:页面风控 部分大厂的产品会过度收集用户信息,包括用户设备信息、在页面的操作轨迹,以此对用户进行分析,并将分析结果作为风控或用户画像的分析,字节系/阿里系产品都有这类骚操作。web端的收集一般会把数据当成参数放在一个静态资源的请求链接上(如xx.gif?data=xxx) 其中xx.gif并不是一个实际的图片 而是服务器收集数据的一个接口
解释2:selenium 自动化测试工具包,提供了程序控制浏览器行为的api;liunx下需安装对应浏览器服务 可headless模式运行