目录
简述
使用IP代理请求目标页面可以避免IP限流。以爬取淘宝商品信息背景为例,如果使用单个IP频繁的请求淘宝网站,就会被淘宝平台识别,返回的接口信息会报“请求被挤爆了....”
现在淘宝PC端商品列表页为了抵御防爬措施,对频繁访问的IP要求重新登录,或者或跳转至一个带有滑块验证的页面,要求用户登录或拖动滑块。同时,淘宝目前已经对一些含有危险性的灰黑IP做限制,能提供云上百万级已知针对性风险的IP黑灰产数据做出判断。目前,淘宝手机端还未做爬虫风险管理,所以使用动态IP代理访问淘宝手机端接口数据还是有效的。
IP代理
IP代理有透明代理、匿名代理、混淆代理和高匿代理。这四种代理,主要是代理服务器端的配置不同,导致其向目标地址发送请求时,REMOTE_ADDR、HTTP_VIA、HTTP_X_FORWARDED_FOR三个变量不同。
REMOTE_ADDR=Proxy IP
HTTP_VIA=Proxy IP
HTTP_X_FORWARDED_FOR=Your IP
透明代理虽然可以直接”隐藏”你的IP,但是还是可以从HTTP_X_FORWARDED_FOR来查到你是谁。
REMOTE_ADDR=Proxy IP
HTTP_VIA=Proxy IP
HTTP_X_FORWARDED_FOR=Proxy IP
匿名代理比透明代理进步一点:别人只能知道你用了代理,无法知道你是谁。
REMOTE_ADDR=Proxy IP
HTTP_VIA=Proxy IP
HTTP_X_FORWARDED_FOR=Random IP address
与匿名代理相同,如果使用了混淆代理,别人还是能知道你在用代理,但是会得到一个假的IP地址,伪装的更逼真
REMOTE_ADDR=Proxy IP
HTTP_VIA=not determined
HTTP_X_FORWARDED_FOR=not determined
使用高匿代理,能让别人根本无法发现你是在用代理,所以是最好的选择。
免费抓取IP代理
网上有很多IP代理供应商,但其价格昂贵,给中小型企业代理了不少的成本预算。如之前使用讯代理、大象代理等。也有不少人私立搭建提供免费IP代理、如西刺、jiangxianli、DATA5U等。本项目将定时去抓取免费IP代理,并将有效IP存入可用IP代理池中。
有关IP代理管理的都在crawl-proxy模块中,通过爬虫任务调度定时触发爬取免费IP代理网站信息,抓取其提供的IP,并存入redis中。
清洗IP代理算法设计
IP代理池有 可用IP代理池、IP代理池、废弃IP代理池,它们的生命周期依次递减。在免费IP代理页面抓取IP后,先把IP存放到IP代理池中,经过验证是否可用,如果可用,则把IP代理池中的IP存放到可用IP代理池中,并将其删除已存在的IP代理池;否则,将IP存放到废弃IP代理池中。
清洗IP是否可用采用的是多线程CompletionService异步非阻塞获取并行任务结果。使用Future和Callable可用获取线程执行结果,但获取方式为阻塞的,根据添加到线程池中的线程顺序,依次获取,获取不到就阻塞。为了更快获取结果,本项目采用CompletionService来实现异步快速收集线程执行结果,并采用基于Socket连接判断IP代理是否可用。具体核心源码如下所示:
public class VerifyProxy {
static ExecutorService threads = Executors.newFixedThreadPool(120);
public VerifyProxy() {
}
public Map<HostPort, Boolean> verifyProxy(List<HostPort> hostPortList) {
Map<HostPort, Boolean> hostPortBooleanMap = Collections.synchronizedMap(new HashMap());
CompletionService<Map<HostPort, Boolean>> cs = new ExecutorCompletionService(this.threads);
int i;
for(i = 0; i < hostPortList.size(); ++i) {
cs.submit(new VerifyProxy.RequestCheck(hostPortList.get(i), hostPortBooleanMap));
}
//this.threads.shutdown();
for(i = 0; i < hostPortList.size(); ++i) {
try {
Map var5 =cs.take().get();
} catch (InterruptedException var6) {
var6.printStackTrace();
} catch (ExecutionException var7) {
var7.printStackTrace();
}
}
return hostPortBooleanMap;
}
class RequestCheck implements Callable<Map<HostPort, Boolean>> {
HostPort hostPort = null;
Map<HostPort, Boolean> map = null;
public RequestCheck(HostPort hostPort, Map<HostPort, Boolean> map) {
this.hostPort = hostPort;
this.map = map;
}
public RequestCheck() {
}
public Map<HostPort, Boolean> call() throws Exception {
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress(hostPort.getHostName(),hostPort.getPort()),2000);
this.map.put(this.hostPort, true);
} catch (IOException e) {
this.map.put(this.hostPort, false);
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return this.map;
}
}
}