从网页源读取随机失败 - Java

Reading from webpage source randomly fails - Java

这是我在 Java 见过的最奇怪的事情。情况是这样的。我尝试阅读 80 多个 URL 而没有任何类型的 API(这真的很糟糕)。这些网页有一种显示我需要的信息的通用方式,因此我通常可以使用一些正则表达式语句找到感兴趣的项目。

这是我正在尝试阅读的示例网页。 Webpage

我有两个非常草率的 classes 来完成这个:

Tester.java。 这里的 Main 方法只是从我的计算机上读取 URL,并为它们中的每一个调用工具 class 中的一个方法,其中 returns 是一个 ArrayList。然后它将 ArrayList 中的所有这些项目添加到更大的 ArrayList 中,这就是我想要的输出。我的程序从来没有做到这一点。

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

public class Tester
{
    public static int d2counter = 0;

    public static void main(String[] args)
    {
        ArrayList<String> database = new ArrayList<>(); 
        ArrayList<String> urls = new ArrayList<>(); 

        try
        {           
            FileReader writer = new FileReader("res/URLs.txt");
            BufferedReader reader = new BufferedReader(writer);     

            while (reader.ready())
            {
                urls.add(reader.readLine());
            }

            for (String i : urls)
            {
                System.out.println(++d2counter + " " + i);
                ArrayList<String> temp = Tools.readURL(i);

                for (String h : temp)
                {
                    database.add(h);
                }
            }

            Tools.outputArraysToFile(database, "output.txt");

            reader.close();
        }
        catch (FileNotFoundException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (IOException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }               
    }
}

Tools.java。这是一个充满静态方法的助手 class。这里唯一感兴趣的方法是 readURL() 方法。

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;

/**
 * Class which will house useful tools for other classes in this program.
 */
public abstract class Tools
{       
    public static ArrayList<String> readURL(String address)
    {
        ArrayList<String> temp = new ArrayList<>();

        try
        {
            // Create a reader to read the webpage.
            BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(address).openStream()));

            // Line variable to be used by Reader.
            String line = "";

            // Phase 1: Navigate to the desired section of the webpage.
            int counter2 = 1;
            while (reader.ready())
            {
                line = reader.readLine();
                counter2++;

                if (line.contains("MAIN CONTENT"))
                {
                    break;
                }
            }

            if (!reader.ready())
            {
                System.err.println("ERROR: Reached bottom of document without finding page title.");
                System.exit(1);
            }

            String name, url, type;
            type = "Default";

            // Find the type.
            for (int i = 0; i < 3; i++)
            {
                line = reader.readLine();

                if (line.matches(".*<B>[A-Za-z\s]+</b>.*"))
                {
                    line = line.substring(line.indexOf("<B>") + 3, line.indexOf("</b>"));
                    line = line.replace("Normal", "");
                    line = line.replace("Exquisite", "");
                    line = line.replace("Elite", "");
                    line = line.trim();
                    if (line.endsWith("s"))
                    {
                        line = line.substring(0, line.length() - 1);
                    }

                    type = line;
                    break;
                }
            }

            // Phase 2: Add data:
            while (!line.contains("END MAIN CONTENT"))
            {
                line = reader.readLine();

                if (line.contains(".gif"))
                {
                    line = line.replaceFirst(".*src=\"", "");
                    url = "classic.battle.net" + line.substring(0, line.indexOf("\""));

                    for (int i = 0; i < 5; i++)
                    {
                        line = reader.readLine();

                        if (line.matches(".*<b>[-A-Za-z\s]+</b>.*"))
                        {
                            line = line.replaceFirst(".*<b>", "");
                            line = line.replaceFirst("</b>.*", "");

                            name = line;
                            temp.add(name + "," + type + "," + url);

                            break;
                        }
                    }
                }
            }

            reader.close();
        }
        catch (IOException e)
        {
            System.err.println("Unable to read from URL.");
            e.printStackTrace();
        }

        return temp;
    }
}

这是奇怪的部分:每次我 运行 程序似乎随机失败。

更奇怪是,如果你访问这些网页,你会发现它们的代码中都有 "MAIN CONTENT",我的 .contains("MAIN CONTENT") 行应该已经检测到。我在辅助打印语句中添加了显示卡住的 URL 并且该行存在的内容。每次我使用调试器时,它都会按照我的要求工作。由于有数千行输入,我似乎无法有效地断点我的方式。我不明白 - 一定有我在这里遗漏的东西。

谢谢大家!

您错误地使用了 ready() 方法——事实上,您根本不应该使用它。它导致您的程序在仍有数据要读取时停止读取。

readLine() 方法就是您所需要的。当你到达文本的末尾时,它 returns null 这就是你用来控制循环的 。标准成语是:

String line = null;
while ((line = reader.readLine()) != null) {
    // process the line
}

ready() returns false时,这并不意味着没有什么可读的,这意味着底层流目前还没有准备好读取,并且有其缓冲区中没有字符。换句话说,BufferedReader 必须等待——可能是几毫秒——才能访问更多字符。在我看来,这是一种 low-level 方法,甚至不应该具有 public 可见性。许多人在你之前掉进了这个陷阱。