如何使用lxml提取文本?

0 投票
1 回答
1048 浏览
提问于 2025-04-15 15:22

我想从某个网站提取一些文本。以下是我想提取文本的网址,目的是制作一个抓取工具。

http://news.search.naver.com/search.naver?sm=tab_hty&where=news&query=times&x=0&y=0

在这个页面上,我想分别提取主题和内容的文本。例如,如果你打开这个页面,你会看到一些文本,

日本东京国际电影节
EPA연합뉴스 世界 | 2009.10.25 (日) 下午 7:21
日本,2009年10月25日。盖耶因在法国导演哈比·莫利亚执导的电影《八次向上》中获得最佳女演员奖。EPA/DAI KUROKAWA

日本东京国际电影节
EPA연합뉴스 世界 | 2009.10.25 (日) 下午 7:18
她在第22届东京电影节的颁奖典礼上得知自己因在法国导演哈比·莫利亚执导的电影《八次向上》中获得最佳女演员奖...

等等,

最后,我想提取的文本格式如下:

主题:日本东京国际电影节
内容:EPA연합뉴스 世界 | 2009.10.25 (日) 下午 7:21 日本,2009年10月25日。盖耶因在法国导演哈比·莫利亚执导的电影《八次向上》中获得最佳女演员奖。EPA/DAI KUROKAWA

主题:...
内容:...

等等。如果有人能帮忙,我会非常感激。提前谢谢!

1 个回答

2

一般来说,要解决这类问题,你首先需要把你感兴趣的网页下载成文本格式(可以用 urllib.urlopen 或其他工具,比如 curl 或 wget,但不要用浏览器,因为你想在任何 Javascript 运行之前先看看网页的样子)。然后,你需要研究这个文本,了解它的结构。在这个例子中,经过一些研究,你会发现相关的部分是(省略了一些不相关的部分,并为了可读性把行分开)……:

<body onload=nx_init();>
 <dl>
 <dt>
<a href="http://news.naver.com/main/read.nhn?mode=LSD&mid=sec&sid1=&oid=091&aid=0002497340"
 [[snipping other attributes of this tag]]>
JAPAN TOKYO INTERNATIONAL FILM FESTIVAL</a>
</dt>
 <dd class="txt_inline">
EPA¿¬ÇÕ´º½º ¼¼°è <span class="bar">
|</span>
 2009.10.25 (ÀÏ) ¿ÀÈÄ 7:21</dd>
 <dd class="sh_news_passage">
 Japan, 25 October 2009. Gayet won the Best Actress Award for her role in the film 'Eight <b>
Times</b>
 Up' directed by French filmmaker Xabi Molia. EPA/DAI KUROKAWA</dd>

接下来,你想要的“主题”是 <a> 标签里的内容,而“内容”则是跟在它后面的 <dd> 标签里的内容(在同一个 <dl> 中)。

你得到的标题包含:

Content-Type: text/html; charset=ks_c_5601-1987

所以你还需要找到一种方法把这种编码转换成 Unicode——我相信这种编码也被称为 'euc_kr',而我的 Python 安装似乎自带了一个解码器,但你也应该检查一下你的安装。

一旦你确定了这些方面,你就可以尝试用 lxml.etree.parse 来解析这个网址——就像很多其他网页一样,它并不能正确解析,因为它并不是一个格式良好的 HTML(你可以用 w3c 的验证工具来查看它有哪些问题)。

因为网络上格式不良的 HTML 非常常见,所以有一些“宽容解析器”可以尝试弥补这些常见错误。在 Python 中最流行的就是 BeautifulSoup,实际上 lxml 也包含了它——从 lxml 2.0.3 版本开始,你可以把 BeautifulSoup 作为底层解析器使用,然后就可以“像是”文档正确解析了一样继续操作,但我觉得直接使用 BeautifulSoup 更简单。

例如,这里有一个脚本可以输出该网址的前几个主题/内容对(它们现在已经改变,最开始和你提供的内容是一样的;-)。你需要一个支持 Unicode 输出的终端(例如,我在 Mac 的 Terminal.App 上运行这个没有问题,设置为 utf-8)——当然,除了用 print 输出,你也可以收集这些 Unicode 片段(比如把它们添加到一个列表中,等你有了所有需要的部分再用 ''.join 把它们连接起来),然后按你想要的方式编码等等。

from BeautifulSoup import BeautifulSoup
import urllib

def getit(pagetext, howmany=0):
  soup = BeautifulSoup(pagetext)
  results = []
  dls = soup.findAll('dl')
  for adl in dls:
    thedt = adl.dt
    while thedt:
      thea = thedt.a
      if thea:
        print 'SUBJECT:', thea.string
      thedd = thedt.findNextSibling('dd')
      if thedd:
        print 'CONTENT:',
        while thedd:
          for x in thedd.findAll(text=True):
            print x,
          thedd = thedd.findNextSibling('dd')
        print
      howmany -= 1
      if not howmany: return
      print
      thedt = thedt.findNextSibling('dt')

theurl = ('http://news.search.naver.com/search.naver?'
          'sm=tab%5Fhty&where=news&query=times&x=0&y=0')
thepage = urllib.urlopen(theurl).read()
getit(thepage, 3)

在 lxml 中的逻辑,或者说“穿着 lxml 外衣的 BeautifulSoup”,其实并没有太大区别,只是各种导航操作的拼写和大小写稍微有些不同。

撰写回答