【问题标题】:Scrapy: Parsing list items onto separate linesScrapy:将列表项解析到单独的行
【发布时间】:2013-10-19 01:13:24
【问题描述】:

尝试使this question 的答案适应我的问题,但没有成功。

这是一些示例 html 代码:

<div id="provider-region-addresses">
<h3>Contact details</h3>
<h2 class="toggler nohide">Auckland</h2>
    <dl class="clear">
        <dt>More information</dt>
            <dd>North Shore Hospital</dd><dt>Physical address</dt>
                <dd>124 Shakespeare Rd, Takapuna, Auckland 0620</dd><dt>Postal address</dt>
                <dd>Private Bag 93503, Takapuna, Auckland 0740</dd><dt>Postcode</dt>
                <dd>0740</dd><dt>District/town</dt>

                <dd>
                North Shore, Takapuna</dd><dt>Region</dt>
                <dd>Auckland</dd><dt>Phone</dt>
                <dd>(09) 486 8996</dd><dt>Fax</dt>
                <dd>(09) 486 8342</dd><dt>Website</dt>
                <dd><a target="_blank" href="http://www.healthpoint.co.nz/default,61031.sm">http://www.healthpoint.co.nz/default,61031...</a></dd>
    </dl>
    <h2 class="toggler nohide">Auckland</h2>
    <dl class="clear">
        <dt>Physical address</dt>
                <dd>Helensville</dd><dt>Postal address</dt>
                <dd>PO Box 13, Helensville 0840</dd><dt>Postcode</dt>
                <dd>0840</dd><dt>District/town</dt>

                <dd>
                Rodney, Helensville</dd><dt>Region</dt>
                <dd>Auckland</dd><dt>Phone</dt>
                <dd>(09) 420 9450</dd><dt>Fax</dt>
                <dd>(09) 420 7050</dd><dt>Website</dt>
                <dd><a target="_blank" href="http://www.healthpoint.co.nz/default,61031.sm">http://www.healthpoint.co.nz/default,61031...</a></dd>
    </dl>
    <h2 class="toggler nohide">Auckland</h2>
    <dl class="clear">
        <dt>Physical address</dt>
                <dd>Warkworth</dd><dt>Postal address</dt>
                <dd>PO Box 505, Warkworth 0941</dd><dt>Postcode</dt>
                <dd>0941</dd><dt>District/town</dt>

                <dd>
                Rodney, Warkworth</dd><dt>Region</dt>
                <dd>Auckland</dd><dt>Phone</dt>
                <dd>(09) 422 2700</dd><dt>Fax</dt>
                <dd>(09) 422 2709</dd><dt>Website</dt>
                <dd><a target="_blank" href="http://www.healthpoint.co.nz/default,61031.sm">http://www.healthpoint.co.nz/default,61031...</a></dd>
    </dl>
    <h2 class="toggler nohide">Auckland</h2>
    <dl class="clear">
        <dt>More information</dt>
            <dd>Waitakere Hospital</dd><dt>Physical address</dt>
                <dd>55-75 Lincoln Rd, Henderson, Auckland 0610</dd><dt>Postal address</dt>
                <dd>Private Bag 93115, Henderson, Auckland 0650</dd><dt>Postcode</dt>
                <dd>0650</dd><dt>District/town</dt>

                <dd>
                Waitakere, Henderson</dd><dt>Region</dt>
                <dd>Auckland</dd><dt>Phone</dt>
                <dd>(09) 839 0000</dd><dt>Fax</dt>
                <dd>(09) 837 6634</dd><dt>Website</dt>
                <dd><a target="_blank" href="http://www.healthpoint.co.nz/default,61031.sm">http://www.healthpoint.co.nz/default,61031...</a></dd>
    </dl>
    <h2 class="toggler nohide">Auckland</h2>
    <dl class="clear">
        <dt>More information</dt>
            <dd>Hibiscus Coast Community Health Centre</dd><dt>Physical address</dt>
                <dd>136 Whangaparaoa Rd, Red Beach 0932</dd><dt>Postcode</dt>
                <dd>0932</dd><dt>District/town</dt>

                <dd>
                Rodney, Red Beach</dd><dt>Region</dt>
                <dd>Auckland</dd><dt>Phone</dt>
                <dd>(09) 427 0300</dd><dt>Fax</dt>
                <dd>(09) 427 0391</dd><dt>Website</dt>
                <dd><a target="_blank" href="http://www.healthpoint.co.nz/default,61031.sm">http://www.healthpoint.co.nz/default,61031...</a></dd>
    </dl>
    </div>

Search again

这是我的蜘蛛;

from scrapy.spider import BaseSpider
from scrapy.selector import HtmlXPathSelector
from webhealth.items1 import WebhealthItem1

class WebhealthSpider(BaseSpider):

name = "webhealth_content1"

download_delay = 5

allowed_domains = ["webhealth.co.nz"]
start_urls = [
    "http://auckland.webhealth.co.nz/provider/service/view/914136/"
    ]

def parse(self, response):
    hxs = HtmlXPathSelector(response)
    results = hxs.select('//*[@id="content"]/div[1]')
    items1 = []
    for result in results:
        item = WebhealthItem1()
        item['url'] = result.select('//dl/a/@href').extract()
        item['practice'] = result.select('//h1/text()').extract()
        item['hours'] = map(unicode.strip, result.select('//div/dl/dt[contains(text(),"Contact hours")]/following-sibling::dd[1]/text()').extract())
        item['more_hours'] = map(unicode.strip, result.select('//div/dl/dt[contains(text(),"More information")]/following-sibling::dd[1]/text()').extract())
        item['physical_address'] = map(unicode.strip, result.select('//div/dl/dt[contains(text(),"Physical address")]/following-sibling::dd[1]/text()').extract())
        item['postal_address'] = map(unicode.strip, result.select('//div/dl/dt[contains(text(),"Postal address")]/following-sibling::dd[1]/text()').extract())
        item['postcode'] = map(unicode.strip, result.select('//div/dl/dt[contains(text(),"Postcode")]/following-sibling::dd[1]/text()').extract())
        item['district_town'] = map(unicode.strip, result.select('//div/dl/dt[contains(text(),"District/town")]/following-sibling::dd[1]/text()').extract())
        item['region'] = map(unicode.strip, result.select('//div/dl/dt[contains(text(),"Region")]/following-sibling::dd[1]/text()').extract())
        item['phone'] = map(unicode.strip, result.select('//div/dl/dt[contains(text(),"Phone")]/following-sibling::dd[1]/text()').extract())
        item['website'] = map(unicode.strip, result.select('//div/dl/dt[contains(text(),"Website")]/following-sibling::dd[1]/a/@href').extract())
        item['email'] = map(unicode.strip, result.select('//div/dl/dt[contains(text(),"Email")]/following-sibling::dd[1]/a/text()').extract())
        items1.append(item)
    return items1

从这里开始,我如何将列表项解析到单独的行中,并在名称字段中使用相应的 //h1/text() 值?目前,我正在一个单元格中获取每个 Xpath 项目的列表。这与我声明 Xpath 的方式有关吗?

谢谢

【问题讨论】:

    标签: parsing xpath scrapy


    【解决方案1】:

    首先,您使用的是results = hxs.select('//*[@id="content"]/div[1]') 所以

        results = hxs.select('//*[@id="content"]/div[1]')
        for result in results:
            ...
    

    将仅循环一个 div,即 &lt;div id="content" class="clear"&gt; 的第一个子 div

    您需要在此//*[@id="content"]/div[1] 中循环每个&lt;dl class="clear"&gt;...&lt;/dl&gt;(使用//*[@id="content"]/div[@class="content"] 可能更容易维护)

            results = hxs.select('//*[@id="content"]/div[@class="content"]/div/dl')
    

    其次,在每次循环迭代中,您都使用绝对 XPath 表达式 (//div...)

    result.select('//div/dl/dt[contains(text(), "...")]/following-sibling::dd[1]/text()')
    

    这将选择 all dd 之后的 dt 匹配从文档根节点开始的文本内容。

    查看this section in Scrapy docs了解详情。

    您需要使用相对 XPath 表达式——在每个 result 范围内的相对表示每个 dl,例如 dt[contains(text(),"Contact hours")]/following-sibling::dd[1]/text()./dt[contains(text(), "Contact hours")]/following-sibling::dd[1]/text()

    “练习”字段仍然可以使用绝对 XPath 表达式 //h1/text(),但您也可以设置一次变量 practice,并在每个 WebhealthItem1() 实例中使用它

            ...
            practice = hxs.select('//h1/text()').extract()
            for result in results:
                item = WebhealthItem1()
                ...
                item['practice'] = practice
    

    以下是您的蜘蛛在进行这些更改后的样子:

    from scrapy.spider import BaseSpider
    from scrapy.selector import HtmlXPathSelector
    from webhealth.items1 import WebhealthItem1
    
    class WebhealthSpider(BaseSpider):
    
        name = "webhealth_content1"
    
        download_delay = 5
    
        allowed_domains = ["webhealth.co.nz"]
        start_urls = [
            "http://auckland.webhealth.co.nz/provider/service/view/914136/"
            ]
    
        def parse(self, response):
            hxs = HtmlXPathSelector(response)
    
            practice = hxs.select('//h1/text()').extract()
            items1 = []
    
            results = hxs.select('//*[@id="content"]/div[@class="content"]/div/dl')
            for result in results:
                item = WebhealthItem1()
                #item['url'] = result.select('//dl/a/@href').extract()
                item['practice'] = practice
                item['hours'] = map(unicode.strip,
                    result.select('dt[contains(.," Contact hours")]/following-sibling::dd[1]/text()').extract())
                item['more_hours'] = map(unicode.strip,
                    result.select('dt[contains(., "More information")]/following-sibling::dd[1]/text()').extract())
                item['physical_address'] = map(unicode.strip,
                    result.select('dt[contains(., "Physical address")]/following-sibling::dd[1]/text()').extract())
                item['postal_address'] = map(unicode.strip,
                    result.select('dt[contains(., "Postal address")]/following-sibling::dd[1]/text()').extract())
                item['postcode'] = map(unicode.strip,
                    result.select('dt[contains(., "Postcode")]/following-sibling::dd[1]/text()').extract())
                item['district_town'] = map(unicode.strip,
                    result.select('dt[contains(., "District/town")]/following-sibling::dd[1]/text()').extract())
                item['region'] = map(unicode.strip,
                    result.select('dt[contains(., "Region")]/following-sibling::dd[1]/text()').extract())
                item['phone'] = map(unicode.strip,
                    result.select('dt[contains(., "Phone")]/following-sibling::dd[1]/text()').extract())
                item['website'] = map(unicode.strip,
                    result.select('dt[contains(., "Website")]/following-sibling::dd[1]/a/@href').extract())
                item['email'] = map(unicode.strip,
                    result.select('dt[contains(., "Email")]/following-sibling::dd[1]/a/text()').extract())
                items1.append(item)
            return items1
    

    我还使用此代码创建了一个 Cloud9 IDE 项目。你可以在https://c9.io/redapple/so_19309960玩它

    【讨论】:

    • 蜘蛛中的小错字,第三行需要webhealth.items1 import WebhealthItem1(自己无法编辑,最小编辑为6个字符)。代码附带的出色解释,非常感谢。
    • 啊,是的,我使用标准的items.py 来测试它。在答案中修复它。
    • 还意识到item['hours'] = map(unicode.strip, result.select('dt[contains(.," Contact hours")]/following-sibling::dd[1]/text()').extract()) 必须声明为hours = hxs.select('//dl/dt[contains(text(),"Contact hours")]/following-sibling::dd[1]/text()').extract(),然后是item['hours'] = hours。慢慢掌握这个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-25
    • 2014-07-14
    • 1970-01-01
    • 1970-01-01
    • 2016-12-04
    • 2017-06-27
    • 1970-01-01
    相关资源
    最近更新 更多