【问题标题】:Presence of junk characters while crawling a Russian website抓取俄罗斯网站时出现垃圾字符
【发布时间】:2015-03-18 14:31:05
【问题描述】:

我正在尝试在 Linux 中抓取俄罗斯网站,但输出似乎是垃圾字符。 该网站以 UTF-8 编码,在阅读时我将编码设置为 UTF-8。然而,这似乎并不能解决问题。 我应该怎么读?

public class Crawl {   
    @SuppressWarnings("unused")
    public static void main(String[] args) {

    URL my_url = new URL("http://www.fmsmoscow.ru/docs/migration_registration/registration.html");
    BufferedReader br = new BufferedReader(new InputStreamReader(my_url.openStream(),"UTF-8"));
    while (null != (strTemp = br.readLine())){
    System.out.println(strTemp);
        }
    }   
}

上面是相同的代码。 我将代码导出为 jar 并将其添加到 Linux 服务器中。 然后我正在执行它以在 Linux 控制台中获取输出。

【问题讨论】:

  • 这个问题的细节还远远不够,无法以任何方式提供帮助。
  • 告诉我你需要什么细节,我会给他们。
  • 1) “网站以 UTF-8 编码” - 您如何确认? 2)“在阅读时我将编码设置为 UTF-8”——这到底是什么意思?请代码。 3)“输出似乎是垃圾字符” - 你在哪里输出什么?
  • 我知道该网站在查看其页面源代码时以 UTF-8 编码。 URL my_url = new URL("fmsmoscow.ru/docs/migration_registration/… br = new BufferedReader(new InputStreamReader(my_url.openStream(),"Cp1251")); while (null != (strTemp = br.readLine())){ System.out. println(strTemp);}
  • 1) 我们说的是Java吗? 2) 为什么即使该站点是 UTF-8 编码的,您仍将编码显式设置为 Cp1251? 3) 请edit your question 并为其添加代码(以及您使用的任何语言的适当标签)。

标签: java linux encoding web-crawler cyrillic


【解决方案1】:

通常,您还可以存储内容二进制文件(按原样),然后查看哪里出错了。比如说像 JEdit 或 NotePad++ 这样可以切换编码的程序员编辑器。它可能会在带有本机 Windows-1251 的 HTML cmets 中滑动。 也许剥离 HTML cmets 会有所帮助。

对于容错解码、错误报告,需要一个CharsetDecoder

CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder(); // ISO_8859_1
decoder.onMalformedInput(CodingErrorAction.IGNORE);
InputStreamReader reader = new InputStreamReader(my_url.openStream(), decoder);

: 请参阅有关 REPLACE、REPORT 的 javadoc。如果你想要更多,方法是不同的。您需要读取输入,将字节放入 ByteBuffer,然后

CoderResult result = decoder(byteBuffer, charBuffer, true /*EOF*/);

要从 UTF-8 中挑选 Cyrillic 序列,可以检查 UTF-8 序列的有效性:

  • 0xxxxxxx
  • 110xxxxx 10xxxxxx
  • 1110xxxx 10xxxxxx 10xxxxxx
  • ...

因此(未经测试):

void patchMixOfUtf8AndCp1251(byte[] bytes, StringBuilder sb) {
    boolean priorWrongUtf8 = false;
    for (int i = 0; i < bytes.length; ++i) {
        byte b = bytes[i];
        if (b >= 0) {
            sb.appendCodePoint((int)b);
            priorWrongUtf8 = false;
        } else {
            int n = highBits(b); // Also # bytes in sequence
            boolean isUTF8 = !priorWrongUtf8
                    && 1 < n && n <= 6
                    && i + n <= bytes.length;
            if (isUTF8) {
                for (int j = 1; j < i + n; ++j) {
                     if (highBits(bytes[j]) != 1) {
                         isUTF8 = false;
                         break;
                     }
                }
            }
            if (isUTF8) {
                sb.append(new String(bytes, i, i + n, StandardCharsets.UTF_8));
                i += n - 1;
            } else {
                // UTF-8 Continuation char must be Cp1252.
                sb.append(new String(bytes, i, i + 1, "Windows-1251"));
            }
            priorWrongUtf8 = !isUTF8;
        }
    }
}

private int highBits(byte b) {
    int n = 0;
    while (n < 8 && ((1 << (7 - n)) & b) != 0) {
        ++n;
    }
    return n;
}

由于西里尔字母不太可能立即连接到 UTF-8,因此使用状态 priorWrongUtf8

【讨论】:

  • 遇到俄语字符就出错了,正在完美爬取页面的其余部分。
  • 添加了补丁功能(未经测试!)。这样的事情可以在有限的范围内发挥作用。
猜你喜欢
  • 1970-01-01
  • 2014-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多