2016-09-21 5 views
2

私はPythonとScrapyにはかなり新しく、Scrapyの助けを借りてネストされたJSONを作成する方法についての私の頭の中で問題を抱えています。Scrapでアイテムデータをネストする

HTMLから必要な要素を選択することは、XPathヘルパーとグーグルの助けを借りて問題にはなりませんでした。私は、私が望むJSON構造体をどうやって取得するのかについてはあまりよく分かりません。

は、私は次のようになり望むJSON構造:私はhttps://stackoverflow.com/a/25096896/6856987を見つけた

<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> 

、私はしかし、私のニーズに合わせて、これを適応することができませんでした:

{"menu": { 
    "Monday": { 
     "alt1": "Item 1", 
     "alt2": "Item 2", 
     "alt3": "Item 3" 
    }, 
    "Tuesday": { 
     "alt1": "Item 1", 
     "alt2": "Item 2", 
     "alt3": "Item 3" 
    } 
}} 

HTMLは次のようになります。私はこれをどうやって達成するかについて、正しい方向で微妙に感謝しています。

編集:Padraicが提供するナッジを使用して、私が達成したいことに一歩近づくことができました。私は以下のことを考え出しました。これは私の前の状況よりも少し改善されています。 JSONはまだ私が望む場所ではありません。

Scrapyクモ:

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

'dmoz.items.DmozItem'を見ることはできますか? – Sam

答えて

0

あなただけの下にlxmlのを使用して、グループにそれらをLISを抽出し、次に例をすべてのULSを見つける必要があると:

あなたを与えるだろう
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) 

{'Monday': {'alt1': 'Item 1', 'alt2': 'Item 2', 'alt3': 'Item 3'}, 
'Tuesday': {'alt1': 'Item 1', 'alt2': 'Item 2', 'alt3': 'Item 3'}} 

をあなたがしたい場合単一のcomporehensionに入れて:

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"))} 

あなたの質問とfollで編集したコードを使って作業する

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 

1つの辞書にあなたのデータを得られますように::

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' 

あなたの新しいよりもあなたの元の質問予想される出力以上に一致するが、私はあなたが何であるかにも利点を見ていないと同じ、必要な出力をため新しいロジックを追加すると"dayOfWeek"などとなります。

+0

ナッジ、パドレイクありがとう。それは私にもう少し近いですが、私はScrapyで動作するようにそれを翻訳するのは苦労しました。私は元の質問をより多くの情報で更新しました。 – Kristoffer

+0

Padraic、あなたの華麗な助けをもう一度ありがとう。 'node.text'をちょうど' node'に変更しなければなりませんでした。そうでなければエラーを投げました( 'AttributeError: 'unicode'オブジェクトには属性 'text''がありません)。興味深いことに、アイテム(または子アイテム)は正しい順序で返されません。実際のクロールでは、金曜日、月曜日、水曜日、月曜日の順に表示されます。しかし、私はそれを働かせることができ、それを回避することができると確信しています。再度、感謝します! – Kristoffer

+0

@Kristoffer、心配する必要はない、dictsは順序付けされていない。もしあなたが注文したいのであれば、通常のdictの代わりに 'collections.OrderedDict'を使うべきです –

関連する問題