我一般是python和网络抓取的新手,我正在尝试使用scrapy从网站提取数据。我遇到的麻烦是我需要的数据都在同一张表中,并且其中许多元素具有相同的标签。 HTML看起来像这样:
<table cellpadding="10"><tr><td valign="top">
</td><td><br>
<br><br><big><b>1-555-555-1111</b></big>
<br><br> LAST, FIRST MIDDLE
<br> <b>Residence address:</b> 1234 street rd , , CITY, 12345
<br> Sex: M
<br> Race: Black, not Hispanic
<br> Birth date: 16 January 1968
<br> Voter ID number: 111111111
<br> Visit the <a href="https://webpage.html">Detail Page of LAST FIRST MIDDLE</a>
<br><br><big><b>1-555-555-1112</b></big>
<br><br> BLAST, BFIRST BM.
<br> <b>Residence address:</b> 1234 ANOTHER ST , #2-213, CITY, 12345
<br> Sex: F
<br> Race: White, not Hispanic
<br> Birth date: 18 December 1933
<br> Voter ID number: 111111112
<br> Visit the <a href="https://webpage.html">Detail Page of LAST FIRST MIDDLE</a>'
<br><br> BBLAST, BBFIRST BBM.
<br> <b>Mailing address:</b> PO BOX 1323, CITY, ST 12345
<br> <b>Residence address:</b> 1234 ANOTHER ST , #2-213, CITY, ST 12345
<br> Sex: F
<br> Race: White, not Hispanic
<br> Birth date: 18 December 1933
<br> Voter ID number: 111111113
<br> Visit the <a href="https://webpage.html">Detail Page of LAST FIRST MIDDLE</a>'
我需要提取数据并将其输出到.csv文件。我需要将此数据存储在CSV中,并且每个人都在自己的行中。我遇到了麻烦,因为由于某些条目在同一电话号码上有多个人,因此我不知道如何提取和保持它的顺序,而在这些条目中并没有为每个人打印电话号码, 就一次。该编号所附的个人都在该单个条目下列出。另外,有时会有一个邮寄地址字段和一个住所地址字段。
我只需要确保提取数据时,为与另一个人共享号码的个人正确填充了电话号码字段,并且我需要确保条目的邮寄地址为空字段那里没有单独的地址。
当我尝试自己拉出任何东西时,我可以提取数据,但是由于输入的内容在电话号码部分中被一个以上的人碰到,它并不能正确地将输入的内容正确地保留给正确的人用一个电话号码来命名。目前,我编写了以下代码,只是为了尝试提取数字和DOB:
import scrapy
class NumspiderSpider(scrapy.Spider):
name = 'numspider'
allowed_domains = ['scraped.site']
start_urls = ['https://scraped.site']
def parse(self, response):
numbers = response.xpath('//td[2]/big/b/text()').extract()
dob = response.xpath(".//td[2]/following::text()[contains(., 'Birth date')]").extract()
yield {'Number': numbers, 'DOB': dob}
不幸的是,这还带来了其他问题,例如我的生日看起来像u'\xa0\xa0\xa0\xa0\xa0Birth date: 16 January 1968\n
和我的数字看起来像u'1-555-555-1111'
。当我将此信息保存到最终的CSV文件中时,我希望它读取16 January 1968
和16 January 1968
答案 0 :(得分:0)
我也不想像生日那样看起来像u'\ xa0 \ xa0 \ xa0 \ xa0 \ xa0生日:1968年1月16日\ n和我的数字看起来像这样u'1-555-555-1111 '。当我将此信息保存到最终的CSV文件中时,我希望它显示为1968年1月16日和1968年1月16日。
这部分很容易解决:dob = map(lambda x: x.strip(), dob)
因为\xa0
被认为是“空白”,因此被其\n
朋友剥夺了。您可以类似地杀死Birth date:
:map(lambda x: re.sub(r'Birth date:\s*', '', x.strip()), dob)
但是,对于您的问题的更大答案,我想为您提供考虑,实际上您所拥有的并不是HTML问题,而是HTML中埋藏了一种文本格式。这种情况就像他们将所有文本都包装在<pre>
中一样:没有选择器会“进入” <pre>
。
但是,由于它是面向行的格式,因此您可以使用一些放置得很好的拆分,以便根据明细记录的缩进和尾随文本将其切成主明细记录。实际上,我很失望string(//td[2])
并没有保留详细记录之间的<br><br>
分割,而是最喜欢的浏览方式。
def parse(self, response):
the_text = response.xpath("string(//td[2])").extract_first().replace("\xa0", " ").lstrip()
# kill the leading "\n" entry and split on flush phone numbers
records = list(filter(lambda x: len(x) > 0, re.split(r'(?m)^([0-9-]+)$', the_text)))
for i in range(0, len(records), 2):
phone = records[i]
rest = records[i+1]
details = re.split(r'(?m)^\s+Visit the Detail Page.*$', rest)
for det in details:
print('detail[ {} ] := {}'.format(phone, det))
# etc etc