【问题标题】:Fetch HTML part in java在java中获取HTML部分
【发布时间】:2018-11-20 10:20:17
【问题描述】:

我在理解如何只下载部分 html 页面时遇到了一些麻烦。我通过URL::openStream 方法和BufferedReader 尝试了传统方式,但我不太确定这种方式是否会促使我下载整个页面。 问题是:我有相当大的 HTML 页面,我需要从中解析 2 个数字,这些数字至少每秒更新一次。上述方式有助于在 2-3 秒内检测一次更改,我想知道是否有办法让它更快。所以我想如果部分获取页面可以帮助我。

【问题讨论】:

  • 或许你可以试试Jsoup?
  • 它从整个页面构建 dom。它相当快,但还不够

标签: java html inputstreamreader


【解决方案1】:

编写帮助程序来读取 url 内容。另一个类中元素的解析器。

public class HTMLReaderHelper {

private final URL currentURL;

HTMLReaderHelper(URL url){
    currentURL = url;
}

public CharIterator charIterator(){
    CharIterator iterator;
    try {
        iterator = new CharIterator();
    } catch(IOException ex){
        return null;
    }
    return iterator;
}

public StringIterator stringIterator(){
    return new StringIterator();
}

class CharIterator implements java.util.Iterator<Character>{

    private InputStream urlStream;

    private boolean isValid;

    private Queue<Character> buffer;

    private CharIterator() throws IOException {
        urlStream = currentURL.openStream();
        isValid = true;
        buffer = new ArrayDeque<>();
    }

    @Override
    public boolean hasNext() {
        char c;
        try {
            c = (char)urlStream.read();
            buffer.add(c);
        } catch (IOException ex) {
            markInvalid();
            return false;
        }
        return c != (char) -1;
    }

    @Override
    public Character next() {
        if(!isValid){
            return null;
        }
        char c;
        try {
            if(buffer.size() > 0){
                return buffer.remove();
            }
            c = (char)urlStream.read();
        } catch (IOException ex) {
            markInvalid();
            return null;
        }
        return (c != (char)-1) ? c : null;
    }

    private void markInvalid(){
        isValid = false;
    }
}

class StringIterator implements java.util.Iterator<String>{

    private CharIterator charPointer;

    private Queue<String> buffer;

    private boolean isValid;

    private StringIterator(){
        charPointer = charIterator();
        isValid = true;
        buffer = new ArrayDeque<>();
    }

    @Override
    public boolean hasNext() {
        String value = next();
        try {
            buffer.add(value);
        } catch (NullPointerException ex){
            markInvalid();
            return false;
        }
        return isValid;
    }

    @Override
    public String next() {
        if(buffer.size() > 0){
            return buffer.remove();
        }
        if(!isValid){
            return null;
        }
        StringBuilder sb = new StringBuilder();
        Character currentChar = charPointer.next();
        if(currentChar == null){
            return null;
        }
        while (currentChar.equals('\n') || currentChar.equals('\r')){
            currentChar = charPointer.next();
            if(currentChar == null){
                return null;
            }
        }
        while (currentChar != Character.valueOf('\n') && currentChar != Character.valueOf('\r')){
            sb.append(currentChar);
            currentChar = charPointer.next();
        }
        return sb.toString();
    }
    private void markInvalid(){
        isValid = false;
    }
}
}

【讨论】:

    【解决方案2】:

    我认为您应该查看如何获取数据(SSE 或 WebSocket),然后尝试订阅该服务。如果这是不可能的尝试更有效的 XML 解析器。我推荐https://vtd-xml.sourceforge.io/ 它可以比JDK 附带的DOM 解析器快10 倍。

    还要小心BufferedReader.readLine(),因为对于您不使用的字符串,存在隐藏的分配成本(这是非常高级的东西,因为您必须考虑 CPU 内存带宽、L1 缓存未命中等)真的需要。

    使用我提到的库的示例:

    byte[] pageInBytes = readAllBytesFromTheURL();
    VTDGen vg = new VTDGen();
    vg.setDoc(pageInBytes);
    vg.parse(false);
    VTDNav vn = vg.getNav();
    
    AutoPilot ap = new AutoPilot(vn);
    
    //Jump to the section that we want to process
    ap.selectXPath("/html/body/div");
    String fileId = vn.toString(vu.getElementFragment());
    

    【讨论】:

    • 非常感谢!顺便说一下page是用Lightstreamer从他们的服务器上获取数据的,我试过直接用,显然不成功
    • 酷,你能接受我的回答吗?我正在寻找堆栈溢出点:)
    • 是的,当然。但是VTD对我不起作用。页面有一些 VTD 无法解析的令牌,所以现在我正在编写自定义阅读器。但我在另一个 XML 文件上试了一下,速度非常快。
    • 你完成后能否分享你的解决方案。我很想知道你的想法。
    猜你喜欢
    • 2014-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-24
    相关资源
    最近更新 更多