网站有许多反爬虫策略,包括但不限于:1、阻止IP地址:目标网站通过阻止某些IP地址来阻止爬虫的访问。2、验证码:目标网站要求用户在提交表单时输入验证码,以便爬虫无法通过表单提交获取数据。3、User-Agent检查:目标网站检查请求的User-Agent信息,以确定请求是否来自爬虫。4、Cookie检查:目标网站通过检查请求中的Cookie信息来确定请求是否来自爬虫。5、反爬虫机器学习模型:目标网站通过训练反爬虫机器模型来识别爬虫程序的请求。这些策略有一个目的,即防止爬虫自动从网站抓取数据。
如果你正在编写爬虫,你需要考虑这些策略,并采取适当的措施来应对。下面提供两个demo,分别演示User-Agent随机和IP地址随机。
1、设置User-Agent随机
String[] userAgents = {
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15",
"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0"
};
Random rand = new Random();
URL url = new URL("http://www.example.com");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
// 设置随机User-Agent
con.setRequestProperty("User-Agent", userAgents[rand.nextInt(userAgents.length)]);
// 发送请求
con.connect();
2、使用代理设置随机IP,您可以使用一个存储多个代理IP和端口的数组,并在每次发送请求时使用数组中的随机值,如下所示:
String[] proxyIps = {
"192.168.0.1:8080",
"192.168.0.2:8080",
"192.168.0.3:8080"
};
Random rand = new Random();
URL url = new URL("http://www.example.com");
// 设置随机代理IP和端口
String[] parts = proxyIps[rand.nextInt(proxyIps.length)].split(":");
String ip = parts[0];
int port = Integer.parseInt(parts[1]);
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ip, port));
HttpURLConnection con = (HttpURLConnection) url.openConnection(proxy);
// 发送请求
con.connect();
为了提升采集效率,对代理IP还需要进行存活检查和有效时间判断。还有一种更简单的设置随机IP的方法,可以使用爬虫代理产品,该产品采用隧道IP技术,可以实现自动IP切换,根据HTTP请求情况进行动态IP分配,如下所示:
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.URL;
import java.util.Random;
class ProxyAuthenticator extends Authenticator {
private String user, password;
public ProxyAuthenticator(String user, String password) {
this.user = user;
this.password = password;
}
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(user, password.toCharArray());
}
}
/**
* 注意:下面代码仅仅实现HTTP请求链接,每一次请求都是无状态保留的,仅仅是这次请求是更换IP的,如果下次请求的IP地址会改变
* 如果是多线程访问的话,只要将下面的代码嵌入到你自己的业务逻辑里面,那么每次都会用新的IP进行访问,如果担心IP有重复,
* 自己可以维护IP的使用情况,并做校验。
*/
public class Demo {
public static void main(String args[]) throws Exception {
// Change in Java 8 Update 111 以上版本需要下面代码
// System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "false");
// System.setProperty("jdk.http.auth.proxying.disabledSchemes", "false");
// 要访问的目标页面
String targetUrl = "http://httpbin.org/ip";
// 代理服务器(产品官网 www.16yun.cn)
String proxyServer = "t.16yun.cn";
int proxyPort = 31111;
// 代理验证信息
String proxyUser = "username";
String proxyPass = "password";
try {
URL url = new URL(targetUrl);
Authenticator.setDefault(new ProxyAuthenticator(proxyUser, proxyPass));
// 创建代理服务器地址对象
InetSocketAddress addr = new InetSocketAddress(proxyServer, proxyPort);
// 创建HTTP类型代理对象
Proxy proxy = new Proxy(Proxy.Type.HTTP, addr);
// 设置通过代理访问目标页面
HttpURLConnection connection = (HttpURLConnection) url.openConnection(proxy);
// 设置KeepAlive
// connection.setRequestProperty("Connection", "keep-alive");
// connection.setRequestProperty("Keep-Alive", "timeout=5, max=100");
// 设置Proxy-Tunnel
// Random random = new Random();
// int tunnel = random.nextInt(10000);
// connection.setRequestProperty("Proxy-Tunnel",String.valueOf(tunnel));
// 解析返回数据
byte[] response = readStream(connection.getInputStream());
System.out.println(new String(response));
} catch (Exception e) {
System.out.println(e.getLocalizedMessage());
}
}
/**
* 将输入流转换成字符串
*
* @param inStream
* @return
* @throws Exception
*/
public static byte[] readStream(InputStream inStream) throws Exception {
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = -1;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
outSteam.close();
inStream.close();
return outSteam.toByteArray();
}
}
上面的代码使用了Java的HttpURLConnection类实现了通过代理IP发送HTTP请求。具体来说,它创建了一个代理服务器地址对象并将其设置为HTTP类型的代理对象,然后通过调用openConnection()方法传递这个代理对象来打开一个到目标页面的连接。随后,它设置了代理验证信息并发送请求。
此外,上面的代码还实现了随机IP请求。具体来说,它定义了一个存储多个代理IP和端口的数组,并使用Java的Random类在每次发送请求时随机选择一个值作为代理IP和端口。