我对Python和Scrapy相当陌生,并且在Scrapy的帮助下如何创建嵌套JSON时遇到了问题。
在XPath Helper和一些谷歌搜索的帮助下,从HTML中选择我想要的元素并不是问题。然而,我不太确定我应该如何获得我想要的JSON结构。
我想要的JSON结构如下:
{"menu": {
"Monday": {
"alt1": "Item 1",
"alt2": "Item 2",
"alt3": "Item 3"
},
"Tuesday": {
"alt1": "Item 1",
"alt2": "Item 2",
"alt3": "Item 3"
}
}}
HTML看起来像:
<ul>
<li class="title"><h2>Monday</h2></li>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<ul>
<li class="title"><h2>Tuesday</h2></li>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
我确实找到了https://stackoverflow.com/a/25096896/6856987,但我无法根据自己的需要进行调整。我非常感谢在正确的方向上轻推我将如何实现这一目标。
编辑:借助Padraic提供的轻推,我设法向我想要完成的任务迈进了一步。我已经提出了以下内容,这比我以前的情况略有改进。 JSON仍然不是我想要的地方。
Scrapy spider:
import scrapy
from dmoz.items import DmozItem
class DmozSpider(scrapy.Spider):
name = "dmoz"
start_urls = ['http://urlto.com']
def parse(self, response):
uls = response.xpath('//ul[position() >= 1 and position() < 6]')
item = DmozItem()
item['menu'] = {}
item['menu'] = {"restaurant": "name"}
for ul in uls:
item['menu']['restaurant']['dayOfWeek'] = ul.xpath("li/h2/text()").extract()
item['menu']['restaurant']['menuItem'] = ul.xpath("li/text()").extract()
yield item
结果JSON:
[
{
"menu":{
"dayOfWeek":[
"Monday"
],
"menuItem":[
"Item 1",
"Item 2",
"Item 3"
]
}
},
{
"menu":{
"dayOfWeek":[
"Tuesday"
],
"menuItem":[
"Item 1",
"Item 2",
"Item 3"
]
}
}
]
这肯定感觉我做了一千零一个错误的事情,希望比我更聪明的人能指出正确的方法。
答案 0 :(得分:0)
你只需要找到所有的uls然后提取lis来对它们进行分组,这个例子使用下面的lxml:
al
哪会给你:
from lxml import html
h = """<ul>
<li class="title"><h2>Monday</h2></li>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<ul>
<li class="title"><h2>Tuesday</h2></li>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>"""
tree = html.fromstring(h)
uls = tree.xpath("//ul")
data = {}
# iterate over all uls
for ul in uls:
# extract the ul's li's
lis = ul.xpath("li")
# use the h2 text as the key and all the text from the remaining as values
# with enumerate to add the alt logic
data[lis[0].xpath("h2")[0].text] = {"alt{}".format(i): node.text for i, node in enumerate(lis[1:], 1)}
print(data)
如果你想把它放在一个comporehension中:
{'Monday': {'alt1': 'Item 1', 'alt2': 'Item 2', 'alt3': 'Item 3'},
'Tuesday': {'alt1': 'Item 1', 'alt2': 'Item 2', 'alt3': 'Item 3'}}
在您的问题中使用已编辑的代码并遵循相同的所需输出:
data = {lis[0].xpath("h2")[0].text:
{"alt{}".format(i): node.text for i, node in enumerate(lis[1:], 1)}
for lis in (ul.xpath("li") for ul in tree.xpath("//ul"))}
这将为您提供一个dict中的数据:
def parse(self, response):
uls = response.xpath('//ul[position() >= 1 and position() < 6]')
item = DmozItem()
# just create an empty dict
item['menu'] = {}
for ul in uls:
# for each ul, add a key value pair {day: {alti: each li_text skipping the first}}
item['menu'][ul.xpath("li/h2/text()").extract_first()]\
= {"alt{}".format(i): node.text for i, node in enumerate(ul.xpath("li[postition() > 1]/text()").extract(), 1)}
# yield outside the loop
yield item
这与您的原始问题预期输出相比您的新输出更多,但我认为您在添加In [15]: d = {"menu":{'Monday': {'alt1': 'Item 1', 'alt2': 'Item 2', 'alt3': 'Item 3'},
'Tuesday': {'alt1': 'Item 1', 'alt2': 'Item 2', 'alt3': 'Item 3'}}}
In [16]: d["menu"]["Tuesday"]
Out[16]: {'alt1': 'Item 1', 'alt2': 'Item 2', 'alt3': 'Item 3'}
In [17]: d["menu"]["Monday"]
Out[17]: {'alt1': 'Item 1', 'alt2': 'Item 2', 'alt3': 'Item 3'}
In [18]: d["menu"]["Monday"]["alt1"]
Out[18]: 'Item 1'
等新逻辑时所做的事情没有任何优势。