每页刮取不同元素位置的表格

时间:2017-06-16 09:30:37

标签: python web-scraping html-table scrapy

设置向上

我正在用Scrapy抓住住房广告,随后用大熊猫分析数据。

根据住房广告,我收集了“大小”,“房间”等房屋特征,随后在字典中产生。

问题

我正在刮的外壳广告在一张桌子上展示了外壳特征,这是完全可以报废的。

但是,广告并非都包含相同的特征,即某些广告会显示所有可能的特征信息,而某些广告则不会。

由于大多数广告都有一些缺失的特征,因此每个广告的表格不同,例如'size'可以在第1行第2列,第2行第1列或其他地方。

检查ad1ad2之间的差异。

我希望能够抓取所有表格,并获得每个广告尽可能多的信息。而且,信息应该分配给正确的变量。即'205m 2 '应分配给'size'而不是'rooms'。

<小时/> 的方法

我目前的方法是首先在列标题中删除变量名,然后将其伴随值分配给变量。即首先刮取列标题,检查是否为变量'size',然后刮取其值并将值赋给变量'size'。

不工作代码:

for i in range(1,5):
        x = response.xpath('//*[@id="details"]/table/tr[{i}]/td[1]/text()').extract_first().strip()
        if 'size' in x:
            size = response.xpath('//*[@id="details"]/table/tr[{i}]/td[2]/text()').extract_first().strip()
        elif 'rooms' in x:
            rooms = response.xpath('//*[@id="details"]/table/tr[{i}]/td[2]/text()').extract_first().strip()

直观地说,这段代码遍历列标题,检查变量,然后将值分配给相应的变量。

但是,我在运行此代码时只收到错误。 我究竟做错了什么? 有更好的方法吗?

2 个答案:

答案 0 :(得分:3)

如果查看HTML结构,每个表行总共有4个单元格,每行字段名称字段值另一个字段名称另一个字段值

<div class="details" id="details" >
  <strong class="sec_name">Property details</strong>

  <table cellpadding="0" cellspacing="0" style="margin-top:0px;">
          <tr>
                    <td class='title'>Ref.: </td>
        <td>Via Scarpellini (1019194)</td>

                        <td class='title'>Ad date: </td>
    <td>
      23/05/2017        </td>
                            </tr>

    <tr>          <td class='title'>Rooms: </td>
      <td> 5</td>
                              <td class='title'>Bathrooms:</td>
      <td> 3</td>
                            </tr>
    <tr>
              <td class='title'>Floor area: </td>
      <td> 292m&sup2;</td>
                                        <td class='title'>Heating: </td>
        <td> Communal</td>
                            </tr>
    ...

一种常见的模式是在每个表行上循环,并在XPath中使用following-sibling轴成对处理单元格。

让我们首先使用scrapy shell中的一个链接(使用CSS选择器div#details table tr)查看每个表行:

$ https://property-italy.immobiliare.it/62225510-penthouses-to-rent-Rome.html
>>> from pprint import pprint
>>> pprint(response.css('div#details table tr'))
[<Selector xpath="descendant-or-self::div[@id = 'details']/descendant-or-self::*/table/descendant-or-self::*/tr" data='<tr>\n\t      \t        \t          \t       '>,
 <Selector xpath="descendant-or-self::div[@id = 'details']/descendant-or-self::*/table/descendant-or-self::*/tr" data='<tr>\n\t        \t        <td class="title"'>,
 <Selector xpath="descendant-or-self::div[@id = 'details']/descendant-or-self::*/table/descendant-or-self::*/tr" data='<tr>\t      <td class="title">Rooms: </td'>,
 <Selector xpath="descendant-or-self::div[@id = 'details']/descendant-or-self::*/table/descendant-or-self::*/tr" data='<tr>\n\t      \t      <td class="title">Flo'>,
 <Selector xpath="descendant-or-self::div[@id = 'details']/descendant-or-self::*/table/descendant-or-self::*/tr" data='<tr>\t      <td class="title">Terrace: </'>,
 <Selector xpath="descendant-or-self::div[@id = 'details']/descendant-or-self::*/table/descendant-or-self::*/tr" data='<tr>\t      <td class="title">Total floor'>,
 <Selector xpath="descendant-or-self::div[@id = 'details']/descendant-or-self::*/table/descendant-or-self::*/tr" data='<tr>\t      <td class="title">Garden: </t'>,
 <Selector xpath="descendant-or-self::div[@id = 'details']/descendant-or-self::*/table/descendant-or-self::*/tr" data='<tr>\t      <td class="title">Furniture: '>]

对于每一行,我们可以检查它是否包含4个<td>个单元格(第一个除外,它是空的):

>>> for row in response.css('div#details table tr'):
...     pprint(row.xpath('.//td'))
... 
[]
[<Selector xpath='.//td' data='<td class="title">Ref.: </td>'>,
 <Selector xpath='.//td' data='<td>Trieste</td>'>,
 <Selector xpath='.//td' data='<td class="title">Ad date: </td>'>,
 <Selector xpath='.//td' data='<td>\n\t\t  13/06/2017\t\t</td>'>]
[<Selector xpath='.//td' data='<td class="title">Rooms: </td>'>,
 <Selector xpath='.//td' data='<td> 4</td>'>,
 <Selector xpath='.//td' data='<td class="title">Bathrooms:</td>'>,
 <Selector xpath='.//td' data='<td> 3</td>'>]
[<Selector xpath='.//td' data='<td class="title">Floor area: </td>'>,
 <Selector xpath='.//td' data='<td> 132m²</td>'>,
 <Selector xpath='.//td' data='<td class="title">Heating: </td>'>,
 <Selector xpath='.//td' data='<td> Autonomous</td>'>]
[<Selector xpath='.//td' data='<td class="title">Terrace: </td>'>,
 <Selector xpath='.//td' data='<td> Yes</td>'>,
 <Selector xpath='.//td' data='<td class="title">Floor: </td>'>,
 <Selector xpath='.//td' data='<td>2</td>'>]
[<Selector xpath='.//td' data='<td class="title">Total floors: </td>'>,
 <Selector xpath='.//td' data='<td>3</td>'>,
 <Selector xpath='.//td' data='<td class="title">Garage:</td>'>,
 <Selector xpath='.//td' data='<td> no</td>'>]
[<Selector xpath='.//td' data='<td class="title">Garden: </td>'>,
 <Selector xpath='.//td' data='<td>Nothing</td>'>,
 <Selector xpath='.//td' data='<td class="title">Condition: </td>'>,
 <Selector xpath='.//td' data='<td>excellent/refurbished</td>'>]
[<Selector xpath='.//td' data='<td class="title">Furniture: </td>'>,
 <Selector xpath='.//td' data='<td>Partly Furnished</td>'>,
 <Selector xpath='.//td' data='<td class="title">Property type: </td>'>,
 <Selector xpath='.//td' data='<td>whole estate</td>'>]

在选择器的data=预览中,您可以看到每个其他<td>都有类"title",所以让我们再次使用CSS选择器获取该信息(td.title):

>>> for row in response.css('div#details table tr'):
...     print(row.css('td.title').get())
... 
None
<td class="title">Ref.: </td>
<td class="title">Rooms: </td>
<td class="title">Floor area: </td>
<td class="title">Terrace: </td>
<td class="title">Total floors: </td>
<td class="title">Garden: </td>
<td class="title">Furniture: </td>

字段值位于每个<td>之后的<td class="title">中。 XPath的following-sibling::td[1]可以在这里使用。这意味着大致&#34;让我<td>是同一个父母的孩子,就像我(兄弟姐妹)一样,但只有我之后的第一个孩子&#34; 。 Scrapy选择器的优点是你可以链接CSS和XPath:

>>> for row in response.css('div#details table tr'):
...     print('---some row---')
...     for cell in row.css('td.title'):
...         print('  ---some cell---')
...         print(cell.xpath('following-sibling::td[1]').get())
... 
---some row---
---some row---
  ---some cell---
<td>Trieste</td>
  ---some cell---
<td>
          13/06/2017        </td>
---some row---
  ---some cell---
<td> 4</td>
  ---some cell---
<td> 3</td>
---some row---
  ---some cell---
<td> 132m²</td>
  ---some cell---
<td> Autonomous</td>
---some row---
  ---some cell---
<td> Yes</td>
  ---some cell---
<td>2</td>
---some row---
  ---some cell---
<td>3</td>
  ---some cell---
<td> no</td>
---some row---
  ---some cell---
<td>Nothing</td>
  ---some cell---
<td>excellent/refurbished</td>
---some row---
  ---some cell---
<td>Partly Furnished</td>
  ---some cell---
<td>whole estate</td>

所以我们有字段名和字段值。让我们在键/值对中组合2:

>>> for row in response.css('div#details table tr'):
...     for cell in row.css('td.title'):
...         print((cell.xpath('string(.)').get(), cell.xpath('string(following-sibling::td[1])').get()))
... 
('Ref.: ', 'Trieste')
('Ad date: ', '\n\t\t  13/06/2017\t\t')
('Rooms: ', ' 4')
('Bathrooms:', ' 3')
('Floor area: ', ' 132m²')
('Heating: ', ' Autonomous')
('Terrace: ', ' Yes')
('Floor: ', '2')
('Total floors: ', '3')
('Garage:', ' no')
('Garden: ', 'Nothing')
('Condition: ', 'excellent/refurbished')
('Furniture: ', 'Partly Furnished')
('Property type: ', 'whole estate')

你可以用dict理解把它变成一个很好的Python dict:

>>> {cell.xpath('string(.)').get():
...      cell.xpath('string(following-sibling::td[1])').get()
...  for row in response.css('div#details table tr')
...   for cell in row.css('td.title')}
{'Ref.: ': 'Trieste', 'Ad date: ': '\n\t\t  13/06/2017\t\t', 'Rooms: ': ' 4', 'Bathrooms:': ' 3', 'Floor area: ': ' 132m²', 'Heating: ': ' Autonomous', 'Terrace: ': ' Yes', 'Floor: ': '2', 'Total floors: ': '3', 'Garage:': ' no', 'Garden: ': 'Nothing', 'Condition: ': 'excellent/refurbished', 'Furniture: ': 'Partly Furnished', 'Property type: ': 'whole estate'}

>>> pprint(_)
{'Ad date: ': '\n\t\t  13/06/2017\t\t',
 'Bathrooms:': ' 3',
 'Condition: ': 'excellent/refurbished',
 'Floor area: ': ' 132m²',
 'Floor: ': '2',
 'Furniture: ': 'Partly Furnished',
 'Garage:': ' no',
 'Garden: ': 'Nothing',
 'Heating: ': ' Autonomous',
 'Property type: ': 'whole estate',
 'Ref.: ': 'Trieste',
 'Rooms: ': ' 4',
 'Terrace: ': ' Yes',
 'Total floors: ': '3'}

我在这里使用XPath string()来获取每个<td>单元格的文本内容,但我也可以使用normalize-space()来删除额外的空格:

>>> {cell.xpath('normalize-space(.)').get():
...      cell.xpath('normalize-space(following-sibling::td[1])').get()
...  for row in response.css('div#details table tr')
...   for cell in row.css('td.title')}
{'Ref.:': 'Trieste', 'Ad date:': '13/06/2017', 'Rooms:': '4', 'Bathrooms:': '3', 'Floor area:': '132m²', 'Heating:': 'Autonomous', 'Terrace:': 'Yes', 'Floor:': '2', 'Total floors:': '3', 'Garage:': 'no', 'Garden:': 'Nothing', 'Condition:': 'excellent/refurbished', 'Furniture:': 'Partly Furnished', 'Property type:': 'whole estate'}
>>> pprint(_)
{'Ad date:': '13/06/2017',
 'Bathrooms:': '3',
 'Condition:': 'excellent/refurbished',
 'Floor area:': '132m²',
 'Floor:': '2',
 'Furniture:': 'Partly Furnished',
 'Garage:': 'no',
 'Garden:': 'Nothing',
 'Heating:': 'Autonomous',
 'Property type:': 'whole estate',
 'Ref.:': 'Trieste',
 'Rooms:': '4',
 'Terrace:': 'Yes',
 'Total floors:': '3'}

答案 1 :(得分:1)

这是事情,不像第一个回答哪个更好地评估你的问题创建了你的项目我以前做过的事情以及我们所有的Scrappy爱好者和它的乐趣是什么诚实,所以任何停机时间,是的,我可以看到自己做这样的事情,但这对你是一种伤害,我在这里回答你的问题,因为我明白不是真的忽略我们如何解决问题,只是重新开始一切并希望你理解它。 Axelrod必须阅读别人的toriel或官方文件才能到达你现在的位置...... Lol坚持,因为它会有点颠簸我提前道歉

所以我写下我对你的回复,就我第一眼看到的那样,我看看这一段代码好吧我很快就意识到这是一个杂乱的格式化项目,所以它是一个很糟糕的项目,我看到了你把这个逻辑炸弹放在我脑子里的代码片段,我真的很生气,因为我不知道你怎么解释你的说法,故障排除是90%显示步骤,日志和错误追溯哈哈......尽管事实上,我瞥见了这个主要的罪恶,然后看看那个片段......看,我希望你只是把这个片段拿到面值以及它如何对你的困境发挥作用。

对于我在范围内()#我将是一个整数对象...字。 x =响应... blah [i] .extract.strip()#The BIGGEST在这里,而不是唯一的问题是你构建了定义项目的调用路径,同时调用它到下一行的事实,同样,当你试图格式化,以便把我放在x = ...它仍然是一个整数......?你做对了......所以不仅不能构建它,它不能被称为格式化字符串 如果&#39;无论什么&#39;在x:#????

事情是,当我第一次开始阅读你的问题时,我开始同情你,因为我已经完成了你所描述的完全相同的事情,房地产公司你抓住了上市网站所以你有竞争力边缘并快速查找属性,每个列表都是销售的联系点......我明白了,我喜欢它。

如果你没有达到我的目的,那就听听它没关系,但是你肯定应该对你使用这些基本功能关于他们的buld和LIMITATIONS的能力有所了解。总是知道那些总是​​远离......快速的pythonic 1-3行逻辑。

对象骚扰和转换的概念。字符串,整数,列表,字典虽然可以混合并以一种方式或另一种方式转换为另一种。真的是一个begginer概念或至少应该是一些东西来表明这一点,因为你当然学习不仅仅是python的本机功能,而是移动其他有用的库...不是说你不能处理scrapy ...但它甚至没有scrapy逻辑问题而不是python ......

你知道发生了什么,但是你知道为什么在这里,正如你所说的那样,每一个页面的实例都被调用为项目化......并不是我们所有的制服都有他们拥有的项目所以它们将作为无值返回..空值...默认情况下,CSV项目导出器参数默认设置为删除非值,因此它会跳过它,这里继续发生的是下一个正在调用项目,但CSV文件中的位置保持不变...然后,项目最终在错误的键下...它变得一团糟。我同情你,努力以我自己的方式提供帮助我想我挑战你试着想一下烤箱简单的解决方案,不需要你试图过度施加自己创造一个轮子但最终得到一个鱼哈哈

由于当一个项目返回为无值时,如何不跳过它可以输入你可以在你的设置文件中设置的任何一个这样的最简单的解决方案,我能想到但不是万无一失,因为它还取决于CSV处理很多不同物品的出口最终不得不按照你想要的方式订购它们吗?那时我会帮助任何蟒蛇学生然后进入谷歌只是有点工作了...你想尝试使用if语句怎么样这个

x = respnse.etcetc#对象已创建,所以我现在可以确定它是否存在 如果x为None:#如果不是......     项目[&#39;等&#39;] =&#34; N / A&#34; ... # 哈!现在什么都没有被跳过 其他:     item [&#39; etc&#39;] = response .... etc etc#返回你的cantnt路径如果项目存在它将被解析... grats

您可以将这个小逻辑直接放入您构建项目的任何部分......如果该项目不存在,那么CSV列的值就是您想要的...... < / p>

和。我去过那里..不仅仅是这个项目的情况和太多必须处理的情况......但是当我第一次听到它进入python时我遇到了一个问题...我的辩护从未与功能在Python但扩展的库和模块...我会上网剃刀,当我厌倦了足够的下降到农场并问它,我个人感谢所有这些火焰给了我一个艰难的时间,因为它让我想永远不会如果你不理解你所说的它毕竟是一种语言,那么我对你所做的编码有什么困惑呢?再次,我希望最好的你希望我可以诚实地帮助你,如果你看看我在这里的所有尝试星级回应和答案爱尔兰试图让人们直接不仅给他一个答案,但我希望你理解答案,并试图灌输这个想法这些日子并没有那么深入到人们的头脑中,基础知识是根本的......爱你是开玩笑的,你可以告诉我它不好玩吗?我的意思是,如果不是,我不会认为你会这样做,除非你为它获得了报酬,这可能是我猜的但是它仍然很有趣你不会我已经学会了如何建立一个研究我的观点是如果你不能举起一把手枪,如果不知道如何把它放在我的脚上,我将如何使用佳能我告诉你你会变得更好而且你会......但是我怎么知道你与python或者主要人员的旅程如何敢于说低级别的发展是你没有提供任何背景学习...至少没有坚实的你没有提到任何关于Scrappy的事情本来很高兴知道我知道因为我每天都看到所以我知道如何调用我的内容和Scrappy ...你提供了一个不完整的部分,你的代码必须有错误...你甚至没有提供爸爸给你的错误,这是我应该让你知道的一个重大罪恶,我们的世界就是如果我们正在做任何类型的故障排除或开发和nah组环境文档是人们了解你所说的内容的关键优惠券,我已经花了太多时间在这上面而且我害怕我是一个聪明人,我不知道,但我真的这么做希望你能达到你想要的目标