网络爬虫内存溢出问题

问题:
SparkStreaming 流式流式任务总是异常退出,看过worker的日志后发现再爬取一个二进制文件时会出现堆内存溢出的问题,将该文件下载下来后发现该文件的大小只有8m左右,我们的任务设置的worker内存为3G,正常来说是不会导致内存溢出的。网络爬虫的框架使用的是webmagic,于是单独对这一段代码进行了debug看看。

报错堆栈信息:
Exception in thread "pool-1-thread-1" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOfRange(Arrays.java:3664) at java.lang.String.<init>(String.java:201) at java.lang.String.substring(String.java:1956) at java.lang.String.trim(String.java:2865) at org.jsoup.nodes.Element.text(Element.java:864) at us.codecraft.xsoup.xevaluator.ElementOperator$AllText.operate(ElementOperator.java:44) at us.codecraft.xsoup.xevaluator.DefaultXElement.get(DefaultXElement.java:31) at us.codecraft.xsoup.xevaluator.DefaultXElement.get(DefaultXElement.java:24) at us.codecraft.xsoup.xevaluator.DefaultXElements.list(DefaultXElements.java:47) at us.codecraft.webmagic.selector.XpathSelector.selectList(XpathSelector.java:31) at us.codecraft.webmagic.selector.HtmlNode.selectElements(HtmlNode.java:80) at us.codecraft.webmagic.selector.HtmlNode.xpath(HtmlNode.java:43)

根据提示得知时xpath部分的代码导致的,我们这行代码如下:
page.getHtml.xpath("///allText()")

查了下xpath的语法,发现没有///这种语法形式,
/ 从根节点选取。

表达式 描述
/ 从根节点选取。
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
. 选取当前节点
.. 选取当前节点的父节点。

这部分代码不止怎么写成了///,但是并不会报入参错误。让我们来看看源码是怎么写的:
一路调试发现此处有一个编译xpath字符串的代码:
public XpathSelector(String xpathStr) { this.xPathEvaluator = Xsoup.compile(xpathStr); }

这部分字符串会根据【// / |】这三个字符做一个拆分:

那么所匹配的路径相当于 ""和allText()

xpath被编译成""的部分除了问题,在查询element的时候会生成大量的对象,导致内存的溢出。为什么会查询到大量的元素呢?
当匹配规则为空的时候,会将每一个标签页当成一个元素。例如下图中的tag="w=w"

还有一个问题,为什么一个二进制文件会有那么多的标签呢?
当this.html ==null的时候,会调用new Html创建,在创建后会对原来的数据添加很多标签
public Html getHtml() { if (this.html == null) { this.html = new Html(this.rawText, this.request.getUrl()); } return this.html; }

T�T�T�*U+U,U-U.U/U0U1U2U3U4U5U6U7U8U9U:U;U <w=w>

那么在调用selectelement的时候,会将每一个标签映射为一个对象,导致创建了2000多个对象。

posted @ 2022-08-07 21:10  桂花载酒少年游O  阅读(211)  评论(0编辑  收藏  举报