当前位置:嗨网首页>书籍在线阅读

04-正则表达式

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

[toc]

2.2.1 正则表达式

如果你对正则表达式还不熟悉,或是需要一些提示,那么你可以查阅 https://docs.python.org/2/howto/regex.html 获得完整介绍。即使你使用过其他编程语言的正则表达式,我依然推荐你一步一步温习一下Python中正则表达式的写法。

由于每章中都可能构建或使用前面章节的内容,因此我建议你按照类似本书代码库的文件结构进行配置。所有代码都可以从代码库的 `code` 目录中运行,以便导入工作正常。如果你希望创建一个不同的结构,请注意需要变更所有来自其他章的导入操作(比如下述代码中的 `from chp1.advanced_link_crawler` )。

当我们使用正则表达式抓取国家(或地区)面积数据时,首先需要尝试匹配 <td> 元素中的内容,如下所示。

>>> import re
>>> from chp1.advanced_link_crawler import download
>>> url = 'http://example.python-scraping.com/view/UnitedKingdom-239'
>>> html = download(url)
>>> re.findall(r'<td class="w2p_fw">(.*?)</td>', html)
['<img src="/places/static/images/flags/gb.png" />',
  '244,820 square kilometres',
  '62,348,447',
  'GB',
  'United Kingdom',
  'London',
  '<a href="/continent/EU">EU</a>',
  '.uk',
  'GBP',
  'Pound',
  '44',
  '@# #@@|@## #@@|@@# #@@|@@## #@@|@#@ #@@|@@#@ #@@|GIR0AA',
  '^(([A-Z]d{2}[A-Z]{2})|([A-Z]d{3}[A-Z]{2})|([A-Z]{2}d{2}    [A-Z]{
2})|([A-Z]{2}d{3}[A-Z]{2})|([A-Z]d[A-Z]d[A-Z]{2})      |([A-Z]{2}d[A-Z]
d[A-Z]{2})|(GIR0AA))$',
  'en-GB,cy-GB,gd',
  '<div><a href="/iso/IE">IE </a></div>']

从上述结果中可以看出,多个国家(或地区)属性都使用了 <td class="w2p_fw"> 标签。如果我们只想抓取国家(或地区)面积,可以只选择第二个匹配的元素,如下所示。

>>> re.findall('<td class="w2p_fw">(.*?)</td>', html)[1]
'244,820 square kilometres'

虽然现在可以使用这个方案,但是如果网页发生变化,该方案很可能就会失效。比如表格发生了变化,去除了第二个匹配元素中的面积数据。如果我们只在当下抓取数据,就可以忽略这种未来可能发生的变化。但是,如果我们希望在未来某一时刻能够再次抓取该数据,就需要给出更加健壮的解决方案,从而尽可能避免这种布局变化所带来的影响。想要该正则表达式更加明确,我们可以将其父元素 <tr> 也加入进来,由于该元素具有ID属性,所以应该是唯一的。

>>> re.findall('<tr id="places_area__row"><td class="w2p_fl"><label
for="places_area" id="places_area__label">Area: </label></td><td
class="w2p_fw">(.*?)</td>', html)
['244,820 square kilometres']

这个迭代版本看起来更好一些,但是网页更新还有很多其他方式,同样可以让该正则表达式无法满足。比如,将双引号变为单引号, <td> 标签之间添加多余的空格,或是变更 area_label 等。下面是尝试支持这些可能性的改进版本。

>>> re.findall('''<tr
id="places_area__row">.*?<tds*class=["']w2p_fw["']>(.*?)</td>''', html)
['244,820 square kilometres']

虽然该正则表达式更容易适应未来变化,但又存在难以构造、可读性差的问题。此外,还有很多其他微小的布局变化也会使该正则表达式无法满足,比如在 <td> 标签里添加 title 属性,或者 trtd 元素修改了它们的CSS类或ID。

从本例中可以看出,正则表达式为我们提供了抓取数据的快捷方式,但是该方法过于脆弱,容易在网页更新后出现问题。幸好,还有更好的数据抽取解决方案,比如我们将在本章介绍的其他抓取库。