小趴菜今年刚毕业,刚来公司第二天。项目经理就分配给他一个某论坛的爬虫需求。小趴菜头疼得很,不过还是在网上找到了使用webmagic爬虫案例,ctrl+cv了一下,改了改就直接上线了。由于周五晚上发帖人比较多,导致小趴菜的爬虫程序崩了,周末两天的数据没能爬到,客户很不满意。
所以我们要注意:当使用webmagic爬取大量的网页时,可能会遇到内存问题,特别是在使用jsoup进行解析时。这是因为jsoup将整个HTML文档加载到内存中,并且需要创建DOM树,这会消耗大量的内存。以下是一些解决这些问题的方法:
1. 设置最大堆大小
可以通过设置JVM参数-Xmx和-Xms来调整JVM堆的最大大小和初始大小。例如,可以将JVM堆的最大大小设置为2GB,初始大小设置为512MB:
java -Xmx2g -Xms512m YourCrawlerMainClass
2. 使用流式解析器
jsoup支持两种解析器:DOM和流式。流式解析器不需要将整个HTML文档加载到内存中,而是逐个标签解析。这可以减少内存消耗。可以通过以下方式使用流式解析器:
// 创建基于流的解析器
Parser parser = Parser.htmlParser().setTrackErrors(10);
// 将解析器传递给Jsoup
Document doc = Jsoup.parse(new URL(url).openStream(), "UTF-8", url, parser);
3. 使用HttpClient
webmagic默认使用JDK的URL类进行网页下载。但是,使用Apache HttpClient可以更好地控制连接池和请求超时。可以通过以下方式使用HttpClient:
// 创建基于HttpClient的下载器
HttpClientDownloader downloader = new HttpClientDownloader();
Spider.create(new MyPageProcessor())
.setDownloader(downloader)
.addUrl("http://www.example.com")
.run();
4. 手动释放内存
当处理大量的网页时,可能需要手动释放内存。可以使用以下代码清理DOM树:
doc.empty();
doc.remove();
5. 优化代码逻辑
优化代码逻辑可以减少不必要的内存消耗。例如,可以尽量避免在循环中创建对象,可以使用缓存来减少重复的网络请求等等。
6. 使用数据库存储数据
当爬取大量的网页时,如果将数据直接存储在内存中,可能会导致内存溢出。这时候可以将数据存储在数据库中,以便后续的处理和分析。一些常见的数据库包括MySQL、MongoDB、Elasticsearch等。
7. 伪代码示例
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.downloader.HttpClientDownloader;
import us.codecraft.webmagic.processor.PageProcessor;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.parser.Parser;
import java.io.IOException;
import java.net.URL;
public class MyPageProcessor implements PageProcessor {
public void process(Page page) {
// 解析页面
Document doc = Jsoup.parse(page.getHtml().get(), "", Parser.xmlParser());
// 处理页面
// ...
// 手动释放内存
doc.empty();
doc.remove();
}
public Site getSite() {
return Site.me();
}
public static void main(String[] args) {
// 创建基于HttpClient的下载器
HttpClientDownloader downloader = new HttpClientDownloader();
// 创建基于流的解析器
Parser parser = Parser.xmlParser().setTrackErrors(10);
Spider.create(new MyPageProcessor())
.setDownloader(downloader)
.addUrl("http://www.example.com")
.run();
}
}