Проблема с восточноевропейскими символами при очистке данных с сайта Европейского парламента - PullRequest
1 голос
/ 10 июня 2010

РЕДАКТИРОВАТЬ: большое спасибо за все ответы и вопросы. Как новичок, я немного ошеломлен, но это отличная мотивация для продолжения изучения питона !!

Я пытаюсь собрать много данных с веб-сайта Европейского парламента для исследовательского проекта. Первым шагом является создание списка всех парламентариев, однако из-за многих восточноевропейских имен и акцентов, которые они используют, я получаю много пропущенных записей. Вот пример того, что доставляет мне неприятности (обратите внимание на акценты в конце фамилии):

<td class="listcontentlight_left">
<a href="/members/expert/alphaOrder/view.do?language=EN&amp;id=28276" title="ANDRIKIENĖ, Laima Liucija">ANDRIKIENĖ, Laima Liucija</a>
<br/>
Group of the European People's Party (Christian Democrats)
<br/>
</td>

До сих пор я использовал PyParser и следующий код:

#parser_names
name = Word(alphanums + alphas8bit)
begin, end = map(Suppress, "><")
names = begin + ZeroOrMore(name) + "," + ZeroOrMore(name) + end

for name in names.searchString(page):
    print(name)

Однако это не улавливает имя из HTML выше. Любой совет, как поступить?

Бест, Томас

P.S .: Вот весь код, который у меня есть:

# -*- coding: utf-8 -*-

import urllib.request
from pyparsing_py3 import *

page = urllib.request.urlopen("http://www.europarl.europa.eu/members/expert/alphaOrder.do?letter=B&language=EN")
page = page.read().decode("utf8")


#parser_names
name = Word(alphanums + alphas8bit)
begin, end = map(Suppress, "><")
names = begin + ZeroOrMore(name) + "," + ZeroOrMore(name) + end

for name in names.searchString(page):
    print(name)

Ответы [ 5 ]

2 голосов
/ 10 июня 2010

Мне удалось показать 31 имя, начинающееся с A, с кодом:

extended_chars = srange(r"[\0x80-\0x7FF]")
special_chars = ' -'''
name = Word(alphanums + alphas8bit + extended_chars + special_chars)

Как заметил Джон, вам нужно больше символов Юникода (extended_chars), а некоторые имена имеют дефис и т. Д. (special chars),Подсчитайте, сколько имен вы получили, и проверьте, имеет ли страница столько же, сколько и я, для 'A'.

Диапазон 0x80-0x87F кодирует 2-байтовые последовательности в utf8, вероятно, всех европейских языков.В примерах разбора есть greetingInGreek.py для греческого и другой пример для разбора корейских текстов.

Если 2 байта недостаточно, попробуйте:

extended_chars = u''.join(unichr(c) for c in xrange(127, 65536, 1))
2 голосов
/ 10 июня 2010

Вы уверены, что написание собственного парсера для выделения битов из HTML - лучший вариант?Возможно, вам будет проще использовать выделенный анализатор HTML. Beautiful Soup , который позволяет вам указать местоположение, в котором вы заинтересованы, используя DOM, поэтому вытащить текст из первой ссылки внутри ячейки таблицы с классом "listcontentlight_left" довольно просто:

1 голос
/ 10 июня 2010

сначала я подумал, что рекомендую попробовать создать собственный буквенный класс из метода unicodedata.category python, который, при наличии символа, скажет вам, какой класс назначен этой кодовой точке в соответствии с юникодом категория персонажей ; это скажет вам, является ли кодовая точка, например, заглавная или строчная буква, цифра или что-то еще.

о второй мысли и напоминающей ответ, который я дал на днях , позвольте мне предложить другой подход. Есть много неявных допущений, от которых мы должны избавиться при переходе от национального к глобальному; одна из них, безусловно, заключается в том, что «символ равен байту», а другая - в том, что «имя человека состоит из букв, и я знаю, какие это возможные буквы». Юникод обширен, и в настоящее время в ЕС существует 23 официальных языка, написанных на трех алфавитах; Точно то, какие символы используются для каждого языка, потребует немало усилий для выяснения. греческий язык использует эти причудливые апострофии и распределяется как минимум по 367 кодам; болгарский язык использует кириллицу с множеством дополнительных символов, уникальных для языка.

так почему бы просто не перевернуть таблицы и не использовать преимущества более широкого контекста, в котором эти имена появляются? я просмотрел некоторые примеры данных, и похоже, что общий шаблон для имен MEP LASTNAME, Firstname с (1) фамилией в (почти) верхнем регистре; (2) запятая и пробел; (3) данные имена в обычном случае . это справедливо даже для более «отклоняющихся» примеров, таких как GERINGER de OEDENBERG, Lidia Joanna, GALLAGHER, Pat the Cope (вау), McGUINNESS, Mairead. Требуется некоторая работа, чтобы восстановить обычный регистр из фамилий (возможно, оставить все строчные буквы на месте, и любые строчные буквы, которым предшествуют другие заглавные буквы), но извлечь имена, на самом деле просто:

fullname  := lastname ", " firstname
lastname  := character+
firstname := character+

это верно - поскольку EUP было так приятно представлять имена, заключенные в тег HTML, вы уже знаете его максимальный экстент, поэтому вы можете просто вырезать этот максимальный экстент и разделить его на две части. на мой взгляд, все, что вам нужно искать, - это первое вхождение последовательности запятой, пробела - все, что до этого является последним, все, что стоит за данными именами . я называю это «силуэтным подходом», поскольку это похоже на то, как форма выглядит, а не на позитив, а на контур, а не на позитив.

как было отмечено ранее, некоторые имена используют дефисы; теперь есть несколько кодовых точек в юникоде, которые выглядят как дефисы. Будем надеяться, что машинистки в Брюсселе были последовательны в их использовании. ах, и есть много фамилий, использующих апострофы, например d'Hondt, d'Alambert. счастливая охота: возможные воплощения включают U + 0060, U + 00B4, U + 0027, U + 02BC и значительное количество двойников. большинство из этих кодовых точек было бы «неправильным» для использования в фамилиях, но когда вы в последний раз видели, как правильно использовались эти точки?

я несколько не доверяю этой модели alphanums + alphas8bit + extended_chars + special_chars; по крайней мере, эта часть alphanums немного приземистая, так как кажется, что она содержит цифры (какие из них? unicode определяет несколько сотен цифр), и что alphas8bit вещь пахнет растворителем, сделанным для другого времени. Unicode концептуально работает в 32-битном пространстве. что значит 8bit? буквы найдены в кодовой странице 852? давай это 2010 год.

ах, и, оглядываясь назад, я вижу, что вы, похоже, разбираете HTML с помощью pyparsing. не делай этого . используйте, например, красивый суп для сортировки разметки ; он неплохо справляется даже с неисправным HTML (большая часть HTML в дикой природе не проверяет), и как только вы поймете, что это за чудесно чудесный API (все, что вам когда-либо понадобится, это, вероятно, метод find()), его будет легко найти именно те фрагменты текста, которые вы ищете.

1 голос
/ 10 июня 2010

Похоже, у вас есть какая-то проблема с кодировкой, если вы получаете западноевропейские имена в порядке (у них также много акцентов и т. Д.!). Покажите нам весь ваш код, а также URL-адрес типичной страницы, которую вы пытаетесь очистить и у которой проблема только для Востока. Отображение фрагмента HTML, который у вас есть, не очень полезен; мы не знаем, через какие преобразования это произошло; по крайней мере, используйте результат функции repr ().

Обновление Символ обидчика в названии этого MEP - U + 0116 (ЛАТИНСКИЙ БУКВЕТ E С ТОЧКОЙ ВЫШЕ). Так что это не входит в pyparsing "alphanums + alphas8bit". Westies (латиница-1) будет соответствовать тому, что у вас уже есть. Я мало знаю о кипаринге; вам нужно найти выражение для разбора, которое включает ВСЕ Юникодные алфавиты ... не только Latin-n, если они начинают использовать кириллицу для болгарских MEP вместо текущей транскрипции в ASCII: -)

Другие наблюдения:

(1) alphaNUMs ... цифры в имени?
(2) имена могут включать апостроф и дефис, например О'Рейли, Фоббарр-Смит

0 голосов
/ 10 июня 2010

Несмотря на то, что BeautifulSoup является стандартом де-факто для синтаксического анализа HTML, в pyparsing есть несколько альтернативных подходов, которые также пригодны и для HTML (безусловно, с опорой на грубую силу reg exps).В частности, одной из функций является makeHTMLTags, которая принимает один строковый аргумент (базовый тег) и возвращает 2 кортежа выражений pyparsing, одно для открывающего тега и одно для закрывающего тега.Обратите внимание, что открывающее выражение тега делает гораздо больше, чем просто возвращает эквивалент "<" + tag + ">".Он также:

  • обрабатывает верхний / нижний регистр самого тега

  • обрабатывает встроенные атрибуты (возвращая их как именованные результаты)

  • обрабатывает имена атрибутов, которые имеют пространства имен

  • обрабатывает значения атрибутов в одинарных, двойных или без кавычек

  • ручкипустые теги, обозначенные завершающим символом '/' перед закрытием '>'

  • , могут быть отфильтрованы для определенных атрибутов с помощью действия синтаксического анализа withAttribute

Поэтому вместо того, чтобы пытаться сопоставить конкретное содержимое имени, я предлагаю вам попробовать сопоставить окружающий тег <a>, а затем получить доступ к атрибуту заголовка.Примерно так:

aTag,aEnd = makeHTMLTags("a")
for t,_,_ in aTag.scanString(page):
    if ";id=" in t.href:
        print t.title

Теперь вы получаете все, что есть в атрибуте title, независимо от набора символов.

...