Страницы

Поиск по вопросам

суббота, 21 декабря 2019 г.

Проблемы с кодировкой при парсинге некоторых сайтов, Golang

#кодировка #парсер #golang #unicode


Доброго времени суток. Столкнулся с такой проблемой: некоторые сайты парсятся адекватно
- текст из формочек достается в читабельной кодировке, а некоторые - нет.
Сначала грешил на UTF-8 на сайте, но ведь Go искаропки только с UTF-8 и работает
по-дефолту
Получаю странику таким кодом: 

func FetchHTML(url string) (string, bool){
    page := ""
    resp, HttpErr := http.Get(url)
    if HttpErr != nil {
        err := HTTPError{url, "", HttpErr.Error()}
        fmt.Println(err.Error())
        return "", false
    }

    defer resp.Body.Close()
    body, IoErr := ioutil.ReadAll(resp.Body)
    if IoErr != nil {
        fmt.Println("IO error: ", IoErr.Error())
        return "", false
    }

    fmt.Println(body)
    page = string(body)
    fetched = true
    return page, true
}


Примеры:
Например, спарсим цитату из любимого всеми ithappens.
Передаю парсеру страничку по адресу http://ithappens.me/story/623
Получаем:

#623
КПД 100%
26 февраля 2009, 11:00

Приятель-программист поделился историей: написал для внутреннего пользования бенчмарк
— в шестнадцати потоках перемножаются здоровенные матрицы. Все скомилировалось, запустилось
и заработало, причем не просто быстро, а слишком быстро.
Матрицы перемножались мгновенно!
После разбора причин происходящего выяснилось, что тестовые матрицы представляли
из себя массивы нулей. Умный интеловский компилято решил не загружать процессор перемножением
и сложением нулей и оптимизировал код таким образом, чтобы сразу заполнить матрицы
необходимого размера нулями.

Rating: 1866
Tags: чудеса техники, программы


Теперь пытаемся сделать то же самое, например, с http://bash.im/quote/435048 
Получаем:

#435048
2015-08-06 12:13
���: �� �������� ���� �������� ������, ��������� 15 ��� ������
���: ����� �������: ����, �� �� �����, �� ��� �� ������
���: �� ���, �� � ����. ��� � �� �����, � ����� ������� ����.
���: ���� �������, � ��� ��� ����� ��� ������ �����, �������� ������������ �� ������
��������� ����� ������ ������
���: �� � � ������� �������, �������� - ���� �������������, ���������.     �������������.
������: ���� �����, 158, 161, 162 (�����, ������, ������), ��������� ��� ��� �� ��������
- ���� ����� ������� �� ������ �� ����������. (�� ����� ���� - �����, ����� ����� ��
���� � ������ ������ ������). �, ������, ���������, �� ��� ��� � �� �������.
���: ��� ��������, ��������
���: � ��� �������, ��� �� ��� ������.
���: ��������� ���������. ��������� �� ���������, �� 4 �����, ������� � ���� - ������
������. ���� ������� �� �����, ������������ ������ - ����� ��� � �������� �����. ���,
��, ����� ����, ����� ����... ���� ����, ��� ���� �������� � ���� �����, ��� ��� �
� ����� ����� ���� ����� ����� ��. � ������: ��-�������, ���� �������� �������.
���: ����!!! � � ���� ��������, �� ������� ������, �� �������!!!
Rating:


Заметил, что в то время как байты текста с ithappens имеют значение 1??, байты текста
bash.im переваливают в значениях за 200.
В чем может быть проблема и как ее решить?
    


Ответы

Ответ 1



Я рекомендую использовать пакет golang.org/x/net/html/charset и собственно его функцию NewReader. Эта функция принимает собственно io.Reader и заголовок Content-Type если он есть. Функция анализирует Content-Type и первые 1024 байта тела и возвращает io.Reader в кодировке UTF-8, а так же ошибку, если она имеет место. Всё просто и круто. Для примера: package main import ( "fmt" "golang.org/x/net/html/charset" "io/ioutil" "net/http" ) func main() { url := "http://bash.im/quote/435048" resp, err := http.Get(url) if err != nil { fmt.Println("HTTP error:", err) return } defer resp.Body.Close() // вот здесь и начинается самое интересное utf8, err := charset.NewReader(resp.Body, resp.Header.Get("Content-Type")) if err != nil { fmt.Println("Encoding error:", err) return } // оп-па-ча, готово body, err := ioutil.ReadAll(utf8) if err != nil { fmt.Println("IO error:", err) return } fmt.Println(string(body)) } Чем хорош этот способ - тем, что он универсален. Можно спокойно применять его для любого сайта. И нет нужды ковыряться в тегах вроде golang кодировка парсер

Ответ 2



Посмотрите на код того же bash.im'а: Страница в кодировке Windows-1251. Чтобы перевести в UTF-8, пользуйтесь пакетами из golang.org/x/text. Например: dec := charmap.Windows1251.NewDecoder() // Разные кодировки = разные длины символов. newBody := make([]byte, len(body)*2) n, _, err := dec.Transform(newBody, body, false) if err != nil { panic(err) } newBody = newBody[:n]

Комментариев нет:

Отправить комментарий