在同一个类下使用更改的xpath刮元素

时间:2019-01-20 09:01:14

标签: python scrapy

我正在尝试抓取“ li”元素,这些元素将根据要添加的“ li”元素的数量而更改其xpath。我不知道如何更好地描述它,所以我将直接进入示例以使其更加清晰。

比方说,这与抓取足球数据有关。该网站的结构如下:

<ul class="stats">
    <p class="results">Man of The Match</p>
    <li>Player12
        <span>1 man of the match</span>
    </li>    
    <p class="results">Goals</p>
    <li>Player1 
        <span>2 goal(s)</span>
    </li>
    <p class="results">Assists</p>
    <p class="results">Yellow Cards</p>
    <li>Player2                                             
    <span>1 yellow card(s)</span>
    </li>
    <p class="results">Red Cards</p>
</ul>

如您所见,p和li元素没有相互“映射”。它们是独立的,即使p是标题,li是内容。刮擦比赛人物很容易,因为要刮擦的元素始终是“ ul / li [1] / span / text()”,而且比赛中只有一个人。但是现在出现了问题。由于目标,助攻等都不属于自己的职业,并且没有列在“ p”下,因此可能会有更多的球员得分,获得牌等。因此,在一个示例中,li [3]是一名球员,进球得分。在另一个示例中(没有目标时),li [3]可能是黄牌。

让我们看看另一个示例:

<ul class="stats">
    <p class="results">Man of The Match</p>
    <li>Player12
        <span>1 man of the match</span>
    </li>    
    <p class="results">Goals</p>
    <li>Player1 
    <span>2 goal(s)</span>
    </li>
    <li>Player2 
    <span>3 goal(s)</span>
    </li>
    <p class="results">Assists</p>
    <p class="results">Yellow Cards</p>
    <li>Player2                                             
    <span>1 yellow card(s)</span>
    </li>
    <li>Player13 
    <span>3 goal(s)</span>
    </li>  
    <p class="results">Red Cards</p>
</ul>

因此,在上面的示例中,我们将为所有锂元素使用不同的xpath。

由于网站的结构尚不清楚,我该如何编写代码以便告诉scrapy哪个“ li”元素属于目标,助攻,黄牌等。

我尝试过:

'player_stats' = extract_with_xpath('ul[@class="stats"]/p/li/text()')

这给了我所有的li元素,但没有跨度。当然,我可以在最后添加跨度,但是比起我无法将其映射到写入项(因为li总是在变化)。但实际上我想获得目标,助攻,黄牌等。

我基本上想知道如何将元素映射到相同的项目,这将根据添加的元素数量(在本例中为目标,辅助等)更改其xpath。我希望我能弄清楚我的问题,因为英语不是我的母语,所以我对可能的错误描述表示歉意。在此先感谢,非常感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

此行:response.css("ul.stats p, ul.stats li")
 以与响应相同的顺序返回pul标签选择器的列表。 之后,您需要分别处理每种类型的节点。

player_data = {}
categoty = ""
for node in response.css("ul.stats p, ul.stats li"):  #returs list of p and li tags selectors in the same order as in response
    if '<p class="results"' in node.extract():
        category = node.css("::text").extract_first()
    if '<li>' in node.extract():
        player = node.css("::text").extract_first().strip()
        if player not in player_data.keys():
            player_data[player]={}
        player_data[player][category]=node.css("span::text").extract_first().strip()


print(player_data)

答案 1 :(得分:0)

您可以使用XPathpreceding-sibling查找前面带有特定键的li元素:

stats = response.css('.stats')
for key in stats.css('p::text').getall():
    for li in stats.xpath('./li[./preceding-sibling::p[1][contains(text(), "{}")]]'.format(key)):
        player = li.xpath('./text()').get()
        value = li.css('span::text').get()