2019-9-15

Java

URL 防重方案

使用MySQL数据库

基于哈希算法去重

将URL进行哈希计算,并将计算结果存储在一个集合或数据库中。每次爬取前先计算URL的哈希值,然后检查该哈希值是否已存在于集合或数据库中。如果存在,则表示URL重复,可以进行过滤。

MySQL 有个 CRC32/64 函数可以生成整型的结果, 使用bigint进行存储; 如果在url列上面加索引会快一些, 但由于url是varchar类型, 字段本身的存储空间和索引占用的存储空间都比较大; 如果加一个crc列, 并且只在这个列上加索引, 索引空间就会小很多,并使用整型加速查询速度避免字符串url全表扫描; SELECT * FROM urls WHERE crc_url = 907060870 AND url = 'http://xxx';

https://www.jianshu.com/p/af6cc7b72dac

基于布隆过滤器的去重

布隆过滤器是一种快速且内存占用较小的数据结构,用于判断一个元素是否存在于集合中。将URL添加到布隆过滤器中,每次爬取前先判断URL是否已存在于布隆过滤器中。如果存在,则表示URL重复,可以进行过滤。 in short 一个元素映射(Hash)成一个位阵列(Bit array)中的一个点; 该点为 1 时有可能存在, 该点为 0 则一定不存在

使用分布式数据库进行去重:

如果爬虫是分布式部署的,可以使用分布式数据库(如Redis)来进行URL去重。每个爬虫节点将已爬取的URL存储在分布式数据库中,并在抓取前先查询数据库判断URL是否已存在。

利用请求指纹进行去重:

除了URL,还可以考虑请求的其他特征(如请求方法、请求参数、请求头等)进行哈希计算,生成请求的唯一指纹。将指纹进行去重判断,避免重复抓取相同的请求。

Webmagic (一个爬虫框架)

webmagic

他的 Selectable API 挺好用的

String htmlString =" <div id=\"logo-doodle-container\">\r\n" + 
				"          <div id=\"logo-doodle-wrapper\">\r\n" + 
				"            <button id=\"logo-doodle-button\">\r\n" + 
				"              <img id=\"logo-doodle-image\" tabindex=\"-1\"></img>\r\n" + 
				"            </button>\r\n" + 
				"          </div>\r\n" + 
				"        </div>";
Selectable html = new Html(htmlString);
//获取元素
Selectable img = html.$("#logo-doodle-image");
//获取元素属性
Selectable tabindexOfimg = html.$("#logo-doodle-image", "tabindex");
System.out.println( img.get() );
System.out.println( "=====================" );
System.out.println( tabindexOfimg.get() );
 
/* 输出
<img id="logo-doodle-image" tabindex="-1">
=====================
-1
*/

处理动态渲染的方案

HtmlUnit

htmlunit 是一款开源的java 页面分析工具,读取页面后,可以有效的使用htmlunit分析页面上的内容。项目可以模拟浏览器运行,被誉为java浏览器的开源实现。是一个没有界面的浏览器,运行速度迅速。

HtmlUnit is a “GUI-Less browser for Java programs”. It models HTML documents and provides an API that allows you to invoke pages, fill out forms, click links, etc… just like you do in your “normal” browser.

It has fairly good JavaScript support (which is constantly improving) and is able to work even with quite complex AJAX libraries, simulating Chrome, Firefox or Internet Explorer depending on the configuration used.

It is typically used for testing purposes or to retrieve information from web sites.

官网

Place all the required jars in your classpath. All of these can be found in the lib directory of the HtmlUnit installation (htmlunit-x.xx.x-bin.zip contains everything you need including all required dependencies).

For maven, you would add:

<dependency>
    <groupId>org.htmlunit</groupId>
    <artifactId>htmlunit</artifactId>
    <version>3.2.0</version>
</dependency>

If you like to use the lastest available snapshot build you have to add the sonatype snapshot repository to your pom repositories section; also (check Twitter for regular information about new snapshot builds).

<repository>
  <id>OSS Sonatype snapshots</id>
  <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
  <snapshots>
    <enabled>true</enabled>
    <updatePolicy>always</updatePolicy>
  </snapshots>
  <releases>
    <enabled>false</enabled>
  </releases>
</repository>
 
 

反爬策略:

  1. 检查用户代理字符串

HtmlUnit在每个请求中发送一个用户代理字符串,可以通过检查该字符串来确定请求是否来自HtmlUnit浏览器。HtmlUnit的用户代理字符串通常包含”HtmlUnit”或”Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 HtmlUnit/2.15”等标识。

  1. 检查请求头信息 HtmlUnit的请求头中可能包含特定的标识信息,可以通过检查请求头来判断是否为HtmlUnit浏览器。例如,检查是否存在特定的请求头字段,如”HtmlUnit-Version”或”X-Requested-With”。

  2. JavaScript检测 HtmlUnit内置了JavaScript解析引擎,您可以编写一段简单的JavaScript代码,通过在网页上执行该代码并检查结果来确定是否在HtmlUnit中执行。例如,可以在网页上添加一个隐藏的元素,然后使用HtmlUnit执行JavaScript来查找该元素是否存在。

PhantomJs

PhantomJS是一个基于Webkit的”无界面”(headless)浏览器, 它会把网站加载到内存并执行页面上的JavaScript, 因为不会展示图形界面, 所以运行起来比完整的浏览器更高效;

PhantomJS在2017年停止了活跃开发,并宣布不再进行进一步的更新和维护

官网

Puppeteer

Puppeteer 是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。Puppeteer 默认以 headless 模式运行,但是可以通过修改配置文件运行“有头”模式。

中文文档 官网

Selenium

Python快速入门&慢速出门 Selenium 是一个用于自动化浏览器操作的工具和框架。它支持多种编程语言,并提供了丰富的API和功能,用于模拟用户在浏览器中的行为,例如点击、填写表单、执行JavaScript等。 Selenium支持多种主流浏览器,包括Chrome、Firefox、Safari、Edge等。它通过不同的驱动程序(例如ChromeDriver、GeckoDriver、SafariDriver)与各种浏览器进行交互。

官方主页 相关API文档

in short 约等于操作浏览器的框架, 可以直接运行在浏览器上, 它支持所有主流的浏览器(包括PhantomJS这些无界面的浏览器)

各版本特性

Selenium 1 : 最初被称为Selenium RC,它通过注入JavaScript来与浏览器进行通信和控制。

Selenium 2 : 引入了WebDriver API,提供了更简洁、易用的方法和操作,用于自动化浏览器操作和进行Web应用程序测试。 原生浏览器支持:Selenium 2 使用原生浏览器功能进行测试操作,而不是通过JavaScript注入。这提高了稳定性、可靠性和兼容性。换句话说支持本地安装的浏览器 多浏览器支持:Selenium 2允许使用不同的浏览器驱动程序(如ChromeDriver、GeckoDriver、SafariDriver)进行跨浏览器测试。

Selenium 3 : W3C WebDriver规范:Selenium 3遵循W3C WebDriver规范,确保更好的跨浏览器兼容性和一致性。 Selenium Grid:Selenium 3集成了Selenium Grid,用于在分布式环境中进行并行测试,支持同时在多个远程节点上执行测试用例。 驱动程序改进:Selenium 3改进了浏览器驱动程序,提供更稳定和可靠的测试环境。

Selenium 4 :

Selenium Grid 4:Selenium 4引入了全新的Selenium Grid,提供了更强大和可扩展的分布式测试能力。新的Grid架构提供了更好的性能、稳定性和容错性。 改进的相对定位策略:Selenium 4引入了一种新的相对定位策略,称为”relative locators”。它允许开发人员通过相对于其他元素的位置来定位元素,例如相对于上方、下方、左侧或右侧的元素。 改进的等待机制:Selenium 4增强了等待机制,提供了更灵活、可定制和可靠的等待条件。新的等待机制使开发人员能够更好地控制测试的执行流程。 DevTools API集成:Selenium 4集成了Chrome DevTools Protocol API,使开发人员能够直接与Chrome浏览器的开发者工具进行交互。这提供了更多的调试和分析功能,以及更高级的浏览器控制能力。 改进的错误处理和调试信息:Selenium 4提供了更详细的错误信息和调试信息,使开发人员能够更轻松地排查和解决问题。 新的HTTP API:Selenium 4引入了一个全新的基于HTTP的WebDriver API,称为”WebDriver over HTTP”。这个API提供了更简单、更直观的方式来与Selenium进行交互,也为将来的扩展和集成提供了更好的基础。 改进的性能和稳定性:Selenium 4对底层架构进行了改进和优化,提高了性能和稳定性,使测试执行更高效、更可靠。

Getting Started

  1. 安装依赖 Install a Selenium library
<dependency>
	<groupId>org.seleniumhq.selenium</groupId>
	<artifactId>selenium-java</artifactId>
	<version>4.9.1</version>
</dependency>
  1. 编码交互
public static void main(String[] args) {
	//构造浏览器驱动 实例
	WebDriver driver = new ChromeDriver();
	//get 访问地址
	driver.get("https://www.baidu.com");
	//等待策略: 您需要确保元素在页面上,并且在尝试与元素交互之前,元素处于可交互状态。
	driver.manage().timeouts().implicitlyWait(Duration.ofMillis(500));
	//获取标题
	String title = driver.getTitle();
	System.out.println(title);
 
	//Find an element 查找网页元素
	WebElement textBox = driver.findElement(By.name("my-text"));
	WebElement submitButton = driver.findElement(By.cssSelector("button"));
 
	// Take action on element  对元素行为
	textBox.sendKeys("Selenium");
	submitButton.click();
 
	//Request element information 获取元素信息
	WebElement message = driver.findElement(By.id("message"));
	String value = message.getText();
 
 
	//执行 Javascript 脚本
	JavascriptExecutor javascriptExecutor = (JavascriptExecutor) driver;
	Object bodyHeight = javascriptExecutor.executeScript("return document.body.scrollHeight;");
	System.out.println("bodyHeight: "+bodyHeight);
 
	//退出
	driver.quit();
}

执行脚本

JavascriptExecutor javascriptExecutor = (JavascriptExecutor) driver;
Object bodyHeight = javascriptExecutor.executeScript("return document.body.scrollHeight;");
System.out.println("bodyHeight: "+bodyHeight);

截图

//全图
TakesScreenshot takesScreenshot = (TakesScreenshot) driver;
File file = takesScreenshot.getScreenshotAs(OutputType.FILE);
 
//局部截图
WebElement message = driver.findElement(By.id("message"));
File file = element.getScreenshotAs(OutputType.FILE);

Chrome (headless模式)

Chrome-headless 模式, Google 针对 Chrome 浏览器 59版 新增加的一种模式, 可以让你不打开UI界面的情况下使用 Chrome 浏览器, 所以运行效果与 Chrome 保持完美一致; 少了真实浏览器加载css,js以及渲染页面的工作。无头测试要比真实浏览器快的多。 可以在无界面的服务器或CI上运行测试,减少了外界的干扰,使自动化测试更稳定。

抓 HTTPS包

WireShark

可以将密钥应用到 Wireshark; 具体路径如下: 菜单栏Edit——Preferences——Protocols——SSL(注意, 不论是SSL还是TLS这里都是SSL, 没有单独的TLS选项), 在(Pre)-Master-Secret log filename中选择刚才设置的变量值

https://blog.csdn.net/jessicaiu/article/details/82178342

Fiddler

Fiddler是一款用于调试和分析HTTP/HTTPS流量的网络抓包工具。它可以截获浏览器和服务器之间的通信,并提供了一系列功能来查看、修改和分析网络请求和响应。

甚至可以抓手机流量

官网

Java 原生 HttpsURLConnection 设置忽略证书验证

import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
 
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
 
 
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");//第一个参数为 返回实现指定安全套接字协议的SSLContext对象; 第二个为提供者
X509TrustManager tm = new X509TrustManager() {
 
	@Override
	public void checkClientTrusted(X509Certificate[] var1, String var2) throws CertificateException {
		// TODO Auto-generated method stub
		
	}
 
	@Override
	public void checkServerTrusted(X509Certificate[] var1, String var2) throws CertificateException {
		// TODO Auto-generated method stub
	}
 
	@Override
	public X509Certificate[] getAcceptedIssuers() {
		// TODO Auto-generated method stub
		return null;
	}
};
X509TrustManager [] tms = {tm};
sslContext.init(null, tms, new SecureRandom());
SSLSocketFactory ssf = sslContext.getSocketFactory();
 
HostnameVerifier ignoreHostnameVerifier = new HostnameVerifier() {  
public boolean verify(String s, SSLSession sslsession) {  
	System.out.println("WARNING: Hostname is not matched for cert.");  
	return true;  
}  
};  
HttpsURLConnection.setDefaultHostnameVerifier(ignoreHostnameVerifier);  
HttpsURLConnection.setDefaultSSLSocketFactory(ssf);