2

我的问题

我正在尝试爬取美国众议院网站上的各个链接,以查找所有列出的个人的华盛顿地址。问题是华盛顿地址的格式不时变化。有时会有项目符号、管道、新行和中断标签,使其难以匹配。


我正在尝试抓取许多页面以检索大致相似的地址:

忽略特殊的空格。它只是为了显示字符串部分的相似性

    1433 朗沃斯大厦办公楼华盛顿特区 20515
     332 Cannon HOB 华盛顿特区 20515
    1641 朗沃斯办公大楼华盛顿特区 20515
    1238 Cannon HOB(回线)
    华盛顿特区 20515
    8293 Longworth House 办公楼 • 华盛顿特区 • 20515
    8293 Longworth House 办公楼 | 华盛顿特区 | 20515

这些中的每一个都将被大量其他文本和 html 标记单独返回。地址甚至可以在地址本身中包含 <br> 或 <br/>。

我想做的是从源字符串中捕获第一个匹配项,并将其设置为变量的值。据我了解,最好使用正则表达式来解决此问题。

更新:

在详细了解了这些日子可能出现的各种方式之后,我决定最好使用不太严格的表达方式。这些地址已显示为项目符号、管道和换行符。也许传达以下内容的表达式是最好的:

[数字][任何东西][“华盛顿”][任何东西][DC|DC][任何东西][五个数字]

显然这太松了。当我只对允许任何一些字符感兴趣时,任何块都会引入段落。

到目前为止,我未能成功匹配以下地址(这些只是众多地址中的一小部分)

4

5 回答 5

2

编辑:似乎第一组数字和“华盛顿”之间的 [任何] 数据必须更加严格才能正常工作。[anything] 部分不应包含任何数字,因为数字是我们用来分隔其中一个地址的开头的。这适用于您给我们的三个网站。

我想说最好的第一步是去掉所有 HTML 标记并替换 ' ' 字符实体:

$input = strip_tags($input);
$input = preg_replace("/&nbsp;/"," ",$input);

然后如果地址匹配(接近)您指定的格式,请执行以下操作:

$results= array();
preg_match("/[0-9]+\s+[^0-9]*?\s+washington,?\s*D\.?C\.?[^0-9]+[0-9]{5}/si",$input,$results);
foreach($result[0] as $addr){
    echo "$addr<br/>";
}

这适用于您提供的三个示例,并且$results[0]应该包含找到的每个地址。

但是,例如,如果地址中包含“Apartment #2”等,这将不起作用,因为它假定最接近“Washington, DC”的数字标记了地址的开头。

以下脚本匹配每个测试用例:

<?php
    $input = "
        1433&nbsp;Longworth House Office Building Washington,  D.C. 20515
         332 Cannon HOB                      Washington   DC   20515
        1641 LONGWORTH HOUSE OFFICE BUILDING WASHINGTON,  DC   20515
        1238 Cannon H.O.B.
        Washington, DC 20515
        8293 Longworth House Office Building • Washington DC • 20515
        8293 Longworth House Office Building | Washington DC | 20515
    ";
    $input = strip_tags($input);
    $input = preg_replace("/&nbsp;/"," ",$input);

    $results= array();
    preg_match_all("/[0-9]+\s+[^0-9]*?washington,?\s*D\.?C\.?[^0-9]*?[0-9]{5}/si",$input,$results);
    foreach($results[0] as $addr){
        echo "$addr<br/>";
    }
于 2009-12-26T02:49:54.987 回答
1

这个正则表达式对输入字符串可以包含的内容采取了更灵活的方法。“华盛顿特区”部分尚未硬编码到其中。地址的不同部分分别被捕获,整个地址将被捕获在$matches[0].

$input = strip_tags($input);
preg_match('/
(\d++)    # Number (one or more digits) -> $matches[1]
\s++      # Whitespace
([^,]++), # Building + City (everything up until a comma) -> $matches[2]
\s++      # Whitespace
(\S++)    # "DC" part (anything but whitespace) -> $matches[3]
\s++      # Whitespace
(\d++)    # Number (one or more digits) -> $matches[4]
/x', $input, $matches);
于 2009-12-26T06:03:10.180 回答
1

编辑:

查看您提到的网站后,我认为以下内容应该有效。假设您在一个名为 的变量中包含您抓取的页面内容$page,那么您可以使用

$subject = strip_tags($page)

从页面中删除所有 HTML 标记;然后应用正则表达式

(\d+)\s*(.*?)\s*washington.{0,5}(DC|D.C.).{0,5}(\d{5})

RegexBuddy 为此生成以下代码(我不懂 PHP):

if (preg_match('/(\d+)\s*(.*?)\s*washington.{0,5}(DC|D.C.).{0,5}(\d{5})/si', $subject, $regs)) {
    $result = $regs[0];
} else {
    $result = "";
}

$regs[1]然后将包含第一个捕获括号(数字)的内容,依此类推。

请注意使用/si修饰符使点匹配换行符,并使正则表达式不区分大小写。

于 2009-12-26T08:33:13.620 回答
1

有一些工具和 API 可以做到这一点。例如,SmartyStreets 的 LiveAddress 就是一个很好的例子。我帮助开发了它,所以我感受到了你的一些痛苦......这是你在问题中提供的样本的输出:

在此处输入图像描述

这是 CSV 输出:

ID,Start,End,Segment,Verified,Candidate,Firm,FirstLine,SecondLine,LastLine,City,State,ZIPCode,County,DpvFootnotes,DeliveryPointBarcode,Active,Vacant,CMRA,MatchCode,Latitude,Longitude,Precision,RDI,RecordType,BuildingDefaultIndicator,CongressionalDistrict,Footnotes
1,4,69,"1433&nbsp;Longworth House Office Building Washington, D.C. 20515",Y,0,,1433 Longworth House Office Building Washington D,,Washington DC 20515-0001,Washington,DC,20515,District of Columbia,AAU1,205150001330,,,,Y,38.89106,-77.01132,Zip5,Residential,S,,AL,Q#X#
2,75,134,332 Cannon HOB Washington DC 20515,Y,0,,332 Cannon Hob,,Washington DC 20515-3226,Washington,DC,20515,District of Columbia,AAU1,205153226996,,,,Y,38.89106,-77.01132,Zip5,Residential,H,Y,AL,H#Q#
3,139,199,"1641 LONGWORTH HOUSE OFFICE BUILDING WASHINGTON, DC 20515",Y,0,,1641 Longworth House Office Building,,Washington DC 20515-0001,Washington,DC,20515,District of Columbia,AAU1,205150001411,,,,Y,38.89106,-77.01132,Zip5,Residential,S,,AL,Q#X#
4,204,247,"1238 Cannon H.O.B.
Washington, DC 20515",Y,0,,1238 Cannon H O B,,Washington DC 20515-0001,Washington,DC,20515,District of Columbia,AAU1,205150001385,,,,Y,38.89106,-77.01132,Zip5,Residential,S,,AL,Q#X#
5,252,316,8293 Longworth House Office Building • Washington DC • 20515,Y,0,,8293 Longworth House Office Building,,Washington DC 20515-0001,Washington,DC,20515,District of Columbia,AAU1,205150001934,,,,Y,38.89106,-77.01132,Zip5,Residential,S,,AL,Q#X#
6,321,381,8293 Longworth House Office Building | Washington DC | 20515,Y,0,,8293 Longworth House Office Building,,Washington DC 20515-0001,Washington,DC,20515,District of Columbia,AAU1,205150001934,,,,Y,38.89106,-77.01132,Zip5,Residential,S,,AL,Q#X#

花了大约2秒。这个API在一定程度上是免费使用的,可能还有其他人喜欢它;我鼓励您四处寻找最适合您的选项...我保证它会比编写自己的正则表达式更好(提示:其背后的代码不是基于正则表达式)。

于 2013-06-13T20:51:48.897 回答
0

你的问题对我来说不是很清楚,但如果我理解正确,我想你可以使用 DOM 解析器来匹配 p 标签,然后检查其中是否有任何单词“Washington”或者电话号码是否与 Washington区域。

于 2009-12-26T02:03:00.027 回答