web-dev-qa-db-ja.com

JavaScript内のデータのスクレイピー

私は scrapy を使用して、Webサイトからのスクレイピングデータを選別しています。ただし、必要なデータはhtml自体ではなく、JavaScriptからのものでした。だから、私の質問は:

そのような場合の値(テキスト値)を取得する方法は?

これは、スクレイピングをスクリーニングしようとしているサイトです: https://www.mcdonalds.com.sg/locate-us/

取得しようとしている属性:住所、連絡先、営業時間。

chromeブラウザ内で「右クリック」、「ソースの表示」を行うと、そのような値自体はHTMLで利用できないことがわかります。


編集する

スライポール、私はあなたが私に言ったことを実行し、admin-ajax.phpを見つけて、遺体を見ましたが、私は今、本当に行き詰っています。

Jsonオブジェクトから値を取得して自分の変数フィールドに格納するにはどうすればよいですか?一般向けに1つの属性だけを実行する方法を共有できれば、同様にスクレイプを始めたばかりの人にも共有できるといいですね。

これが私のコードです

Items.py

class McDonaldsItem(Item):
name = Field()
address = Field()
postal = Field()
hours = Field()

McDonalds.py

from scrapy.spider import BaseSpider
from scrapy.selector import HtmlXPathSelector
import re

from fastfood.items import McDonaldsItem

class McDonaldSpider(BaseSpider):
name = "mcdonalds"
allowed_domains = ["mcdonalds.com.sg"]
start_urls = ["https://www.mcdonalds.com.sg/locate-us/"]

def parse_json(self, response):

    js = json.loads(response.body)
    pprint.pprint(js)

長い編集を求めて、つまり、属性にjson値をどのように保存しますか?例えば

*** item ['address'] = *取得方法****

PS、これが役立つかどうかはわかりませんが、コマンドラインでこれらのスクリプトを実行します

スクレイピークロールmcdonalds -o McDonalds.json -t json(すべてのデータをjsonファイルに保存するため)

感謝の気持ちを十分に強調できません。私はあなたにこれを尋ねるのは一種の不合理であることを知っています、あなたがこれのための時間を持っていなくても完全に大丈夫でしょう。

22

(これを_scrapy-users_メーリングリストに投稿しましたが、Paulの提案により、Shellコマンドインタラクションで回答を補完するため、ここに投稿します。)

通常、サードパーティのサービスを使用してデータの視覚化(マップ、テーブルなど)をレンダリングするWebサイトは、何らかの方法でデータを送信する必要があり、ほとんどの場合、このデータにはブラウザーからアクセスできます。

この場合、検査(つまり、ブラウザーによって行われた要求の調査)により、データがPOST要求から https://www.mcdonalds.com。 sg/wp-admin/admin-ajax.php

したがって、基本的に、必要なすべてのデータが、Nice json形式で使用できる状態になっています。

ScrapyはShellコマンドを提供しており、スパイダーを作成する前にWebサイトを考える人にとって非常に便利です。

_$ scrapy Shell https://www.mcdonalds.com.sg/locate-us/
2013-09-27 00:44:14-0400 [scrapy] INFO: Scrapy 0.16.5 started (bot: scrapybot)
...

In [1]: from scrapy.http import FormRequest

In [2]: url = 'https://www.mcdonalds.com.sg/wp-admin/admin-ajax.php'

In [3]: payload = {'action': 'ws_search_store_location', 'store_name':'0', 'store_area':'0', 'store_type':'0'}

In [4]: req = FormRequest(url, formdata=payload)

In [5]: fetch(req)
2013-09-27 00:45:13-0400 [default] DEBUG: Crawled (200) <POST https://www.mcdonalds.com.sg/wp-admin/admin-ajax.php> (referer: None)
...

In [6]: import json

In [7]: data = json.loads(response.body)

In [8]: len(data['stores']['listing'])
Out[8]: 127

In [9]: data['stores']['listing'][0]
Out[9]: 
{u'address': u'678A Woodlands Avenue 6<br/>#01-05<br/>Singapore 731678',
 u'city': u'Singapore',
 u'id': 78,
 u'lat': u'1.440409',
 u'lon': u'103.801489',
 u'name': u"McDonald's Admiralty",
 u'op_hours': u'24 hours<br>\r\nDessert Kiosk: 0900-0100',
 u'phone': u'68940513',
 u'region': u'north',
 u'type': [u'24hrs', u'dessert_kiosk'],
 u'Zip': u'731678'}
_

つまり、スパイダーで上記のFormRequest(...)を返し、次にコールバックで_response.body_からjsonオブジェクトをロードし、最後にリスト内の各ストアのデータ_data['stores']['listing']_を作成します必要な値を持つアイテム。

このようなもの:

_class McDonaldSpider(BaseSpider):
    name = "mcdonalds"
    allowed_domains = ["mcdonalds.com.sg"]
    start_urls = ["https://www.mcdonalds.com.sg/locate-us/"]

    def parse(self, response):
        # This receives the response from the start url. But we don't do anything with it.
        url = 'https://www.mcdonalds.com.sg/wp-admin/admin-ajax.php'
        payload = {'action': 'ws_search_store_location', 'store_name':'0', 'store_area':'0', 'store_type':'0'}
        return FormRequest(url, formdata=payload, callback=self.parse_stores)

    def parse_stores(self, response):
        data = json.loads(response.body)
        for store in data['stores']['listing']:
            yield McDonaldsItem(name=store['name'], address=store['address'])
_
21
R. Max

選択したブラウザで https://www.mcdonalds.com.sg/locate-us/ を開いたら、「検査」ツールを開きます(たぶん、ChromeまたはFirefox)、[ネットワーク]タブを探します。

「XHR」(XMLHttpRequest)イベントをさらにフィルタリングすると、この本文でhttps://www.mcdonalds.com.sg/wp-admin/admin-ajax.phpへのPOSTリクエストが表示されます

action=ws_search_store_location&store_name=0&store_area=0&store_type=0

POSTリクエストへの応答は、必要なすべての情報を含むJSONオブジェクトです

import json
import pprint
...
class MySpider(BaseSpider):
...
    def parse_json(self, response):

        js = json.loads(response.body)
        pprint.pprint(js)

これは次のようなものを出力します:

{u'flagicon': u'https://www.mcdonalds.com.sg/wp-content/themes/mcd/images/storeflag.png',
 u'stores': {u'listing': [{u'address': u'678A Woodlands Avenue 6<br/>#01-05<br/>Singapore 731678',
                           u'city': u'Singapore',
                           u'id': 78,
                           u'lat': u'1.440409',
                           u'lon': u'103.801489',
                           u'name': u"McDonald's Admiralty",
                           u'op_hours': u'24 hours<br>\r\nDessert Kiosk: 0900-0100',
                           u'phone': u'68940513',
                           u'region': u'north',
                           u'type': [u'24hrs', u'dessert_kiosk'],
                           u'Zip': u'731678'},
                          {u'address': u'383 Bukit Timah Road<br/>#01-09B<br/>Alocassia Apartments<br/>Singapore 259727',
                           u'city': u'Singapore',
                           u'id': 97,
                           u'lat': u'1.319752',
                           u'lon': u'103.827398',
                           u'name': u"McDonald's Alocassia",
                           u'op_hours': u'Daily: 0630-0100',
                           u'phone': u'68874961',
                           u'region': u'central',
                           u'type': [u'24hrs_weekend',
                                     u'drive_thru',
                                     u'mccafe'],
                           u'Zip': u'259727'},

                        ...
                          {u'address': u'60 Yishuan Avenue 4 <br/>#01-11<br/><br/>Singapore 769027',
                           u'city': u'Singapore',
                           u'id': 1036,
                           u'lat': u'1.423924',
                           u'lon': u'103.840628',
                           u'name': u"McDonald's Yishun Safra",
                           u'op_hours': u'24 hours',
                           u'phone': u'67585632',
                           u'region': u'north',
                           u'type': [u'24hrs',
                                     u'drive_thru',
                                     u'live_screening',
                                     u'mccafe',
                                     u'bday_party'],
                           u'Zip': u'769027'}],
             u'region': u'all'}}

必要なフィールドを抽出します。

Scrapyで送信するFormRequest()で、おそらく「X-Requested-With:XMLHttpRequest」ヘッダーを追加する必要があります(検査ツールで要求ヘッダーを確認すると、ブラウザーがそれを送信します)

7
paul trmbrth