从欧洲议会网站搜索数据时,东欧人物出现问题

时间:2010-06-10 09:58:54

标签: python html-parsing screen-scraping

编辑:非常感谢所有答案,并提出了一些观点。作为一个新手,我有点不知所措,但这是继续学习python的一个很好的动力!!

我正试图从欧洲议会网站上搜集大量研究项目的数据。第一步是创建一个所有议员名单,但由于许多东欧名字和他们使用的口音,我得到了很多缺失的条目。这是一个给我带来麻烦的例子(注意姓氏末尾的重音):

<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 个答案:

答案 0 :(得分:2)

我能够以代码显示31个以A开头的名字:

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

正如John注意到你需要更多的unicode字符(extended_chars)而某些名字有更多的字符(special chars)。计算您收到的姓名数量,并检查页面是否与“A”的计数相同。

范围0x80-0x87F编码可能是所有欧洲语言的utf8中的2个字节序列。在pyparsing示例中,希腊语有greetingInGreek.py,韩语文本解析有其他例子。

如果2个字节不够,请尝试:

extended_chars = u''.join(unichr(c) for c in xrange(127, 65536, 1))

答案 1 :(得分:2)

您确定编写自己的解析器来从HTML中选择位是最佳选择吗?您可能会发现使用专用的HTML解析器更容易。 Beautiful Soup,它允许您指定您对使用DOM感兴趣的位置,因此从表格单元格中的第一个链接中提取文本并使用“listcontentlight_left”类非常简单:

soup = BeautifulSoup(htmlDocument)
cells = soup.findAll("td", "listcontentlight_left")
for cell in cells:
  print cell.a.string

答案 2 :(得分:1)

如果你的西欧名字很好(你也有很多口音等等),看起来你有某种编码问题。向我们展示您的所有代码以及您尝试抓取的典型页面的URL,并且具有仅限East的问题。显示你所拥有的html片段并没有多大用处;我们不知道它经历了什么样的转变;至少,使用repr()函数的结果。

更新该MEP名称中的违规字符为U + 0116(上面带有字母的LATIN LETTER CAPITAL E)。所以它不包含在pyparsing的“alphanums + alphas8bit”中。 Westies(拉丁语-1)将适合你已经拥有的东西。我对pyparsing知之甚少;你需要找到一个包含所有unicode字母表的pyparsing表达式...不仅仅是Latin-n,以防他们开始使用Cyrillic作为保加利亚语MEP而不是当前转录成ASCII: - )

其他观察:

(1)alphaNUMs ...名称中的数字?
(2)名称可包括撇号和连字符,例如O'Reilly,Foughbarre-Smith

答案 3 :(得分:1)

起初我以为我会建议尝试从python的unicodedata.category方法构建一个自定义字母类,当给出一个字符时,它会告诉你该代码点被赋予哪个类来赋予{{{ 3}};这会告诉你代码点是否是例如大写或小写字母,数字或其他。

关于unicode character category的第二个想法和回忆,让我提出另一种方法。从国家到全球,我们必须摆脱许多隐含的假设;其中一个肯定是'一个字符等于一个字节',另一个是'一个人的名字由字母组成,我知道可能的字母是什么'。 unicode很大,欧盟目前有23种官方语言,用三个字母书写;究竟是什么字符用于每种语言将涉及相当多的工作来弄清楚。希腊使用那些花哨的叛逆者,分布在至少367个代码点上;保加利亚语使用西里尔字母和一系列独特的字符。

那么为什么不简单地转换表并利用这些名称出现的更大的上下文?通过一些示例数据,看起来像 MEP名称的一般模式是LASTNAME, Firstname,(1)(几乎)大写的姓氏; (2)逗号和空格; (3)普通情况下的给定名称。这甚至适用于GERINGER de OEDENBERG, Lidia JoannaGALLAGHER, Pat the Cope(哇),McGUINNESS, Mairead等更“偏离”的例子。从姓氏中恢复普通案件需要做一些工作(可能会留下所有小写字母,小写字母以小写字母开头),但实际上提取名字是简单:

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

这是正确的 - 因为EUP很好地呈现了包含在HTML标记中的名称,您已经知道它的最大范围,因此您可以删除最大范围并将其分成两部分。正如我所看到的,所有你需要寻找的是第一次出现的逗号序列,空格 - 在此之前的所有内容都是最后一个,任何人的特定名称背后的东西。我称之为“轮廓方法”,因为它看起来像负面,轮廓,而不是正面,形成的形式。

如前所述,有些名字使用连字符;现在unicode中有几个看起来像连字符的代码点。让我们希望布鲁塞尔那边的打字员在使用方面是一致的。啊,有许多使用撇号的姓氏,如d'Hondtd'Alambert。快乐狩猎:可能的化身包括U + 0060,U + 00B4,U + 0027,U + 02BC和相当数量的相似之处。大多数这些代码点在姓氏中使用都是“错误的”,但是最后一次你看到正确使用了这些代码是什么时候?

我有点不信任alphanums + alphas8bit + extended_chars + special_chars模式;至少那个alphanums部分有点柏忌,因为它似乎包括数字(哪一个?unicode定义了几百个字符),而alphas8bit这个东西确实为另一个时间制造了溶剂。 unicode概念上适用于32位空间。什么是8bit意味着什么?在代码页852中找到的字母?来吧,这是2010年。

啊,回头看,我看到你似乎正在用pyparsing解析HTML。 不要那样做使用例如an answer i gave the other day用于整理标记;它甚至可以处理错误的HTML(大多数HTML在野外都无法验证),而且一旦你了解它,那就是奇妙的API(你所需要的只是find()方法)它很简单准确地捕捉到你正在寻找的那些片段。

答案 4 :(得分:0)

尽管BeautifulSoup是HTML解析的事实上的标准,但是pyparsing还有一些替代方法可以用于HTML(当然比暴力强制reg exps更好)。一个函数特别是makeHTMLTags,它接受一个字符串参数(基本标记),并返回一个2元组的pyparsing表达式,一个用于开始标记,一个用于结束标记。请注意,开始标记表达式不仅仅返回“&lt;”+ tag +“&gt;”的等价物。它还:

  • 处理标签的上/下壳体 本身

  • 处理嵌入的属性 (将它们作为命名结果返回)

  • 处理具有的属性名称 名称空间

  • 处理单引号,双引号或无引号的属性值

  • 处理空标记,如a所示 在结束'&gt;'

  • 之前尾随'/'
  • 可以针对具体进行过滤 使用withAttribute的属性 解析行动

因此,我建议您尝试匹配周围的<a>标记,然后访问title属性,而不是尝试匹配特定的名称内容。像这样:

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

现在你得到title属性中的任何内容,无论字符集如何。

相关问题