0 准备工作
在拙作使用Python的Text Processing方法爬取IMDb TOP 250榜单电影列表中,我们用Python写了一个简单的小爬虫,来爬取IMDb TOP 250电影榜单。通过阅读该篇文章,相信读者应该对URL、网页外观与其源代码之间的关系有一个简单的了解。
在篇末,我提到使用正则表达式也可以很轻松的完成这项工作。本篇将介绍使用正则表达式工具RegexBuddy来提取IMDb TOP 250榜单的方法。
首先,先对正则表达式这个名词进行一个科普,它不是一个很可怕的jargon,你通过查阅维基百科,可以发现,它的意思是“描述某种规则的表达式”,它还有很多别名,比如“正规表达式”。你可以理解为一个正则表达式可以描述一个pattern,比如扑克牌中的三带一,你想在按一定顺序排列的牌堆里找出所有的三带一这个组合,你便对我说“三带一”(一个表达式),然后我来识别这个表达式,并把符合三带一排列的牌组找出来。正则表达式是一种pattern的描述方法,很巧地,很多工具可以识别这种描述方法(而我只能识别“三带一”这种描述方法),并起到筛选的作用。根据表达式找到目标内容的过程叫做“匹配”。拿到匹配到的内容,你就可以进行修剪了。
其次,你的终端上要装一个RegexBuddy,你可以理解为它是一个识别正则表达式并进行匹配的工具。我使用的版本是3.6.0,这个资源请自行找寻,本文并不提供任何违反法律法规的下载通道。
在你的Google Chrome浏览器中打开IMDb TOP 250电影榜单,并使用'Ctrl + U'组合键调出网页源代码,再打开你刚刚安装好的RegexBuddy,你便完成了所有准备工作。
1 提取第一个电影信息
打开RegexBuddy,你会发现一个这样的界面。对于一个商学院的学生来说,这样的界面还是太吓人了。
RegexBuddy Initiation但要告诉大家的是,为了提取这个电影榜单的信息,大部分功能我们是暂时用不到的。
在左上角的Match/Replace/Split选项卡中选择Replace,在中间一行Create/Test/Debug...选项卡中选择Test,如果你的操作正确,它现在的界面应该变成了这个样子。
RegexBuddy Replace/Test Mode现在,回到我们之前找到的源代码界面,全选源代码,将其复制粘贴至Test选项卡上半部分的空白区域。
View Source 复制到这个区域现在,我们找到包含某一部电影,如排名在145位的1961年美国电影《纽伦堡审判》,所有信息的代码段,复制到Replace选项卡的上半部分的空白区域。
<td class="titleColumn">
145.
<a href="/title/tt0055031/?pf_rd_m=A2FGELUUNOQJNL&pf_rd_p=2398042102&pf_rd_r=0MN1ASG8REVJVVVN01RG&pf_rd_s=center-1&pf_rd_t=15506&pf_rd_i=top&ref_=chttp_tt_145"
title="Stanley Kramer (dir.), Spencer Tracy, Burt Lancaster" >Judgment at Nuremberg</a>
<span class="secondaryInfo">(1961)</span>
</td>
<td class="ratingColumn imdbRating">
<strong title="8.2 based on 48,165 user ratings">8.2</strong>
</td>
<td class="ratingColumn">
<div class="seen-widget seen-widget-tt0055031 pending" data-titleid="tt0055031">
<div class="boundary">
<div class="popover">
复制到这个位置
我们可以看到,复制的这段语句中,有很多以颜色高亮出来的字符。这些字符,是正则表达式中保留字符,我们在每一个高亮出来的字符之前加一个转义符''。
匹配到了《纽伦堡审判》的信息可以看到,RegexBuddy匹配到了所有符合我们输入pattern的字符串,并用黄色高亮来表示。
到此为止,我们已经通过输入一个pattern成功匹配到了一个字符串。
2 观察目标字符串结构
我们现在已经匹配到电影《纽伦堡审判》的信息所在的字符串,我们将其命名为目标字符串。其实,所有的目标字符串都有一定的结构,它们之间有相同的部分,也有不同的部分,我们将这些不同的部分命名为特异部分。我们要输入的正则表达式,其作用就是将这个结构中的特异部分用一定的规则表示出来。
我在下图中,用高亮将每个目标字符串的特异部分标出。在这些特异部分中,有一些是我们关注的,包括排名,导演,主演一,主演二,题名,年份,投票数,评分,我们将之称为目标信息。将目标信息用蓝色下划线标出。
特异部分/目标信息在此例中,所有的特异部分所处的context都是一样的,如第二行,‘145’前面有六个空格,后面有一个句点。所有的目标字符串的排名这个位置,前方都有六个空格,后面都有一个句点。同样地,导演Stanley Kramer前边是'title="',后面是' (dir.)'。表示评分信息的那一行,可以看到它的结构是"xx based on xxx user ratings". 这些目标字符串的一致性,为我们提取目标信息提供了很大的便利。
3 使用正则表达式.*
匹配特异部分
本篇文章,将不对正则表达式的细则进行讲解,只重点讲解两个保留字符。
第一个字符是句点.
。一个句点可以表示一个换行符之外的字符,如果你在正则表达式输入框输入一个句点,它将匹配除了换行符之外的每一个字符。
第二个字符是星号*
。星号本身不代表任何pattern,但它跟在句点之后,可以表示任意长度的除了换行符之外的字符串。如果在正则表达式输入框中输入.*
,它将匹配全文的每一行(不包含换行符)。
在此例中,我们尝试性地将所有特异部分替换成.*
。Bravo! 可以看到,所有的目标字符串都被匹配到了。
4 捕获和提取目标信息
接下来,我们将对我们感兴趣的信息进行捕获。捕获是正则表达式应用中的一个重要功能。通常情况下,我们使用圆括号()
进行捕获,我们首先试着捕获排名数。在排名数的位置加上一对圆括号,你便捕获了榜单中每一部电影的排名数。
我们试着提取一下这个排名数。 选择Test选项卡中Replace命令,并在下拉菜单中选择List All Replacement,勾选Update Automatically. 这个Replace命令的作用,是将正则表达式匹配到的字符进行替换,替换的内容由用户自定义。而List All Replacement则是将每处替换的结果显示在Test选项卡下半部分的空白中。
List All Replacement现在,我们将在Replace选项卡下半部分的空白中,输入用于替换的文本。我们使用
$
来引用捕获的分组。如在这里,我们输入$1
,这个命令的作用,是将所有匹配到的文本(目标字符串),替换成该字符串中的指定捕获值(这里用1来指定排名)。
引用并显示捕获值
可以看到,在Test选项卡下半部分的空白中,出现了每一处替换后的内容,即我们捕获的排名。我们可以使用相同的办法,对所有我们看兴趣的内容一一捕获、引用并显示。
全部捕获后的结果通过调整引用的顺序,可以对显示内容的顺序进行更改,但是,当信息量大,捕获分组较多时,使用数字来引用捕获就会显得十分混乱。这里,我们可以给每一个捕获起一个名字,如给排名数起名字,可以在正则表达式中这样表示,(?<rank>.*)
。
这样,我们想引用排名数时,就可以使用排名数分组的名称‘rank’来引用它了,正确的引用命令是${rank}
。
试着将所有我们感兴趣的信息起名,最后的正则表达式长这个样子。
<td class="titleColumn">
(?<rank>.*)\.
<a href=".*"
title="(?<dir>.*) \(dir\.\), (?<star1>.*), (?<star2>.*)" >(?<title>.*)</a>
<span class="secondaryInfo">\((?<year>.*)\)</span>
</td>
<td class="ratingColumn imdbRating">
<strong title=".* based on (?<users>.*) user ratings">(?<rating>.*)</strong>
</td>
<td class="ratingColumn">
<div class="seen-widget seen-widget-.* pending" data-titleid="(?<id>.*)">
我们试着在替换文本框中输入${rank} ${title} ${year} ${dir} ${star1} ${star2} ${users} ${rating} ${id}
,可以看到每一部电影的信息都显示在了下方,总共有250条记录。
5 导出目标数据
RegexBuddy支持将我们提取出的结果导出为任意支持格式的文件。我们比较感兴趣的文件类型是CSV文件。
通常情况下,将空格改为逗号即可解决格式问题。但是我们注意到,评分数信息中本身就含有逗号,这会影响CSV文件对列的判断,因此,我们使用CSV文件可以识别的另一个分隔符——制表符。
在替换文本框中,我们使用'\t'来表示制表符。可以看到显示结果中已经出现了制表符。修改完毕后,可以使用Test选项卡中的另存为命令,选择Save Test Result命令,保存类型选择All files,并手动将扩展名改为CSV.
添加制表符并保存结果 选择All files并手动规定扩展名到此为止,我们便提取了榜单中所有我们感兴趣的信息。
IMDb.CSV正则表达式在text processing中的应用非常广泛,许多语言都有兼容正则表达式的功能包,在这里,推荐一篇讲解其具体规则的文章——《正则表达式30分钟入门教程》。RegexBuddy还有更多强大的功能,比如将正则表达式转换成兼容不同语言的代码段等等。此例中,我们用到的只是它所有功能中最为肤浅的一部分。
这个方法,是我本科时期在上海财经大学金融科学实验中心打杂的时候学到的,比使用Python编写爬虫法更快更直观,应付普通的数据提取应该是绰绰有余了,不敢藏私,特此记录。如果您发现任何问题或有任何建议,欢迎指正或讨论。
by JohnnyMOON
COB @UIUC
EM: gengyug2@illinois.edu
网友评论