Извлеките многострочный контент javascript из тега <script>, используя Scrapy

Я пытаюсь извлечь данные из этого тега скрипта с помощью Scrapy:

<script> var hardwareTemplateFunctions; var storefrontContextUrl = ''; jq(function() { var data = new Object(); data.hardwareProductCode = '9054832'; data.offeringCode = 'SMART_BASIC.TLF12PLEAS'; data.defaultTab = ''; data.categoryId = 10001; data.bundles = new Object(); data.bundles['SMART_SUPERX.TLF12PLEAS'] = { signupFee: parsePrice('0'), newMsisdnFee: parsePrice('199'), upfrontPrice: parsePrice('1099'), monthlyPrice: parsePrice('499'), commitmentTime: parsePrice('12'), offeringTitle: 'SMART Super', offeringType: 'VOICE', monthlyPrice: parsePrice('499'), commitmentTime: 12 }; data.bundles['SMART_PLUSS.TLF12PLEAS'] = { signupFee: parsePrice('0'), newMsisdnFee: parsePrice('199'), upfrontPrice: parsePrice('1599'), monthlyPrice: parsePrice('399'), commitmentTime: parsePrice('12'), offeringTitle: 'SMART Pluss', offeringType: 'VOICE', monthlyPrice: parsePrice('399'), commitmentTime: 12 }; data.bundles['SMART_BASIC.TLF12PLEAS'] = { signupFee: parsePrice('0'), newMsisdnFee: parsePrice('199'), upfrontPrice: parsePrice('2199'), monthlyPrice: parsePrice('299'), commitmentTime: parsePrice('12'), offeringTitle: 'SMART Basis', offeringType: 'VOICE', monthlyPrice: parsePrice('299'), commitmentTime: 12 }; data.bundles['SMART_MINI.TLF12PLEAS'] = { signupFee: parsePrice('0'), newMsisdnFee: parsePrice('199'), upfrontPrice: parsePrice('2999'), monthlyPrice: parsePrice('199'), commitmentTime: parsePrice('12'), offeringTitle: 'SMART Mini', offeringType: 'VOICE', monthlyPrice: parsePrice('199'), commitmentTime: 12 }; data.bundles['KONTANT_KOMPLETT.REGULAR'] = { signupFee: parsePrice('0'), newMsisdnFee: parsePrice('0'), upfrontPrice: parsePrice('3499'), monthlyPrice: parsePrice('0'), commitmentTime: parsePrice('0'), offeringTitle: 'SMART Kontant', offeringType: 'PREPAID', monthlyPrice: parsePrice('0'), commitmentTime: 0 }; data.reviewJson = new Object(); hardwareTemplateFunctions = hardwareTemplateFunctions(data); hardwareTemplateFunctions.init(); data.reviewSummaryBox = hardwareTemplateFunctions.reviewSummaryBox; accessoryFunctions(data).init(); additionalServiceFunctions(data).init(); }); function parsePrice(str) { var price = parseFloat(str); return isNaN(price) ? 0 : price; } var offerings = {}; </script> 

Я хочу получить данные из каждого раздела, которые выглядят следующим образом:

  data.bundles['SMART_SUPERX.TLF12PLEAS'] = { signupFee: parsePrice('0'), newMsisdnFee: parsePrice('199'), upfrontPrice: parsePrice('1099'), monthlyPrice: parsePrice('499'), commitmentTime: parsePrice('12'), offeringTitle: 'SMART Super', offeringType: 'VOICE', monthlyPrice: parsePrice('499'), commitmentTime: 12 }; 

а затем извлекать данные из каждого поля и получать окончательные данные, например, с помощью upfrontPrice (например, 1099 в этом примере).

Я попытался извлечь каждый объект, используя это:

 items = response.xpath('//script/text()').re("data.bundles\[.*\](.*)") 

Однако это дает мне только первую строку данных. ( = { ). Итак, как мне это сделать? Есть ли лучший способ извлечения этих данных из тега скрипта?

Edit: Когда я использую items = response.xpath('//script/text()').re("data.bundles\[.*\] = {((?s).*) };") Кажется чтобы получить только последний блок (тот, у которого есть data.bundles['KONTANT_KOMPLETT.REGULAR'] )

Как мне получить список всех из них?

3 Solutions collect form web for “Извлеките многострочный контент javascript из тега <script>, используя Scrapy”

Следующее регулярное выражение кажется правильным:

 r"data\.bundles\[[^\]]*\] = {([^}]*)}" 

* в регулярных выражениях жадный – он всегда будет стараться соответствовать как можно больше, поэтому я использую [^\]] чтобы убедиться, что я буду соответствовать ближайшему ] . Я делаю то же самое с {} скобками. Кроме того, мне не о чем беспокоиться . не соответствует новой строке.

Если вы не хотите играть с регулярными выражениями, есть js2xml , который анализирует код Javascript и преобразует его в документ lxml. Затем вы можете использовать XPath для запроса вещей из операторов Javascript. (отказ от ответственности: я написал и поддерживаю js2xml)

Вот пример кода о том, как получить эти назначения data.bundles :

 import scrapy selector = scrapy.Selector(text="""<script> var hardwareTemplateFunctions; var storefrontContextUrl = ''; jq(function() { var data = new Object(); data.hardwareProductCode = '9054832'; data.offeringCode = 'SMART_BASIC.TLF12PLEAS'; data.defaultTab = ''; data.categoryId = 10001; data.bundles = new Object(); data.bundles['SMART_SUPERX.TLF12PLEAS'] = { signupFee: parsePrice('0'), newMsisdnFee: parsePrice('199'), upfrontPrice: parsePrice('1099'), monthlyPrice: parsePrice('499'), commitmentTime: parsePrice('12'), offeringTitle: 'SMART Super', offeringType: 'VOICE', monthlyPrice: parsePrice('499'), commitmentTime: 12 }; data.bundles['SMART_PLUSS.TLF12PLEAS'] = { signupFee: parsePrice('0'), newMsisdnFee: parsePrice('199'), upfrontPrice: parsePrice('1599'), monthlyPrice: parsePrice('399'), commitmentTime: parsePrice('12'), offeringTitle: 'SMART Pluss', offeringType: 'VOICE', monthlyPrice: parsePrice('399'), commitmentTime: 12 }; data.bundles['SMART_BASIC.TLF12PLEAS'] = { signupFee: parsePrice('0'), newMsisdnFee: parsePrice('199'), upfrontPrice: parsePrice('2199'), monthlyPrice: parsePrice('299'), commitmentTime: parsePrice('12'), offeringTitle: 'SMART Basis', offeringType: 'VOICE', monthlyPrice: parsePrice('299'), commitmentTime: 12 }; data.bundles['SMART_MINI.TLF12PLEAS'] = { signupFee: parsePrice('0'), newMsisdnFee: parsePrice('199'), upfrontPrice: parsePrice('2999'), monthlyPrice: parsePrice('199'), commitmentTime: parsePrice('12'), offeringTitle: 'SMART Mini', offeringType: 'VOICE', monthlyPrice: parsePrice('199'), commitmentTime: 12 }; data.bundles['KONTANT_KOMPLETT.REGULAR'] = { signupFee: parsePrice('0'), newMsisdnFee: parsePrice('0'), upfrontPrice: parsePrice('3499'), monthlyPrice: parsePrice('0'), commitmentTime: parsePrice('0'), offeringTitle: 'SMART Kontant', offeringType: 'PREPAID', monthlyPrice: parsePrice('0'), commitmentTime: 0 }; data.reviewJson = new Object(); hardwareTemplateFunctions = hardwareTemplateFunctions(data); hardwareTemplateFunctions.init(); data.reviewSummaryBox = hardwareTemplateFunctions.reviewSummaryBox; accessoryFunctions(data).init(); additionalServiceFunctions(data).init(); }); function parsePrice(str) { var price = parseFloat(str); return isNaN(price) ? 0 : price; } var offerings = {}; </script>""") 

(эта первая часть состоит в том, чтобы получить ввод HTML в селекторе Scrapy)

 import js2xml import pprint data_bundles = {} for script in selector.xpath('//script/text()').extract(): # this is how you turn Javascript code into an XML document (lxml document in fact) jstree = js2xml.parse(script) # then, we're interested in assignments of data.bundles object for a in jstree.xpath('//assign[left//property/identifier/@name="bundles" and right/object]'): # the assigned property is give by a <string> property from a <bracketaccessor> bundle_prop = a.xpath('./left/bracketaccessor/property/string/text()') if bundle_prop is not None: curr_prop = bundle_prop[0] data_bundles[curr_prop] = {} # the left object is assigned an object (inside a <right> element) # let's loop on the <property> elements) # the values are either numbers or string arguments of a function call for prop in a.xpath('./right/object/property'): data_bundles[curr_prop][prop.xpath('@name')[0]] = prop.xpath('.//number/@value | .//string/text()')[0] pprint.pprint(data_bundles) 

Это то, что вы получаете от этого:

 {'KONTANT_KOMPLETT.REGULAR': {'commitmentTime': '0', 'monthlyPrice': '0', 'newMsisdnFee': '0', 'offeringTitle': 'SMART Kontant', 'offeringType': 'PREPAID', 'signupFee': '0', 'upfrontPrice': '3499'}, 'SMART_BASIC.TLF12PLEAS': {'commitmentTime': '12', 'monthlyPrice': '299', 'newMsisdnFee': '199', 'offeringTitle': 'SMART Basis', 'offeringType': 'VOICE', 'signupFee': '0', 'upfrontPrice': '2199'}, 'SMART_MINI.TLF12PLEAS': {'commitmentTime': '12', 'monthlyPrice': '199', 'newMsisdnFee': '199', 'offeringTitle': 'SMART Mini', 'offeringType': 'VOICE', 'signupFee': '0', 'upfrontPrice': '2999'}, 'SMART_PLUSS.TLF12PLEAS': {'commitmentTime': '12', 'monthlyPrice': '399', 'newMsisdnFee': '199', 'offeringTitle': 'SMART Pluss', 'offeringType': 'VOICE', 'signupFee': '0', 'upfrontPrice': '1599'}, 'SMART_SUPERX.TLF12PLEAS': {'commitmentTime': '12', 'monthlyPrice': '499', 'newMsisdnFee': '199', 'offeringTitle': 'SMART Super', 'offeringType': 'VOICE', 'signupFee': '0', 'upfrontPrice': '1099'}} 

Для получения дополнительной информации о схеме XML, которую вы получаете с помощью js2xml.parse() , вы можете проверить https://github.com/redapple/js2xml/blob/master/SCHEMA.rst

Этот скрипт требует установки Mozilla Firefox и python-selenium , а также я провел тесты с помощью файла script.txt, который содержит скрипт, окруженный тегом. Вот код:

 from selenium import webdriver script_content = open("script.txt").read() #Removing script tags exec_script = script_content.replace("<script>", "").replace("</script>", "") #Removing jq function call exec_script = exec_script.replace("jq(function() {", "").replace("});", "") #Setting some helper functions to avoid javascript errors helper_functions = """function hardwareTemplateFunctions(){ return {init: function(){}};}; accessoryFunctions = additionalServiceFunctions = hardwareTemplateFunctions;""" #Returning data variable return_statement = "return data;" wd = webdriver.Firefox() #Getting data variable in result result = wd.execute_script(helper_functions + exec_script + return_statement) 

Переменная result выглядит так:

 {u'bundles': {u'KONTANT_KOMPLETT.REGULAR': {u'commitmentTime': 0, u'monthlyPrice': 0, u'newMsisdnFee': 0, u'offeringTitle': u'SMART Kontant', u'offeringType': u'PREPAID', u'signupFee': 0, u'upfrontPrice': 3499}, u'SMART_BASIC.TLF12PLEAS': {u'commitmentTime': 12, u'monthlyPrice': 299, u'newMsisdnFee': 199, u'offeringTitle': u'SMART Basis', u'offeringType': u'VOICE', u'signupFee': 0, u'upfrontPrice': 2199}, u'SMART_MINI.TLF12PLEAS': {u'commitmentTime': 12, u'monthlyPrice': 199, u'newMsisdnFee': 199, u'offeringTitle': u'SMART Mini', u'offeringType': u'VOICE', u'signupFee': 0, u'upfrontPrice': 2999}, u'SMART_PLUSS.TLF12PLEAS': {u'commitmentTime': 12, u'monthlyPrice': 399, u'newMsisdnFee': 199, u'offeringTitle': u'SMART Pluss', u'offeringType': u'VOICE', u'signupFee': 0, u'upfrontPrice': 1599}, u'SMART_SUPERX.TLF12PLEAS': {u'commitmentTime': 12, u'monthlyPrice': 499, u'newMsisdnFee': 199, u'offeringTitle': u'SMART Super', u'offeringType': u'VOICE', u'signupFee': 0, u'upfrontPrice': 1099}}, u'categoryId': 10001, u'defaultTab': u'', u'hardwareProductCode': u'9054832', u'offeringCode': u'SMART_BASIC.TLF12PLEAS', u'reviewJson': {}, u'reviewSummaryBox': None} 
  • Прокси-IP для инфраструктуры Scrapy
  • Куки-файлы Python Scrapy не работают, но работают в PHP cURL-коде
  • как хранить снимки на Amazon S3?
  • scrapy, как сделать свой собственный графический планировщик
  • Scrapy - как идентифицировать уже очищенные URL-адреса
  • scrap scrap на всех страницах, у которых есть этот синтаксис
  • Запуск нескольких пауков один за другим
  • Неустранимая ошибка C1083: Не удается открыть файл include: 'openssl / opensslv.h'
  •  
    Interesting Posts for Van-Lav

    «ImportError: невозможно импортировать имя StanfordNERTagger» в NLTK

    Количество наиболее часто встречающихся 100 слов из предложений в Dataframe Pandas

    Использование pickle.dump – TypeError: должно быть str, а не байтами

    pyserial – можно записать в последовательный порт из потока a, сделать блокировку чтения из потока b?

    Desktop Launcher для скрипта Python запускает программу с неправильным контуром (Linux)

    Как я могу перебирать два списка параллельно?

    Python: определение объединения регулярных выражений

    Каков хороший размер (в байтах) для файла журнала?

    Как я могу количественно определить разницу между двумя изображениями?

    SQLAlchemy INSERT IGNORE

    Как искать словарные ключи в списке

    Недопустимый парсер URL в python

    Отображение новых строк в содержимом, представленном пользователем (веб-приложение Python)

    Каковы лучшие практики Python для констант ключа словаря?

    Отправлять словарь, но передавать различные параметры в функции

    Python - лучший язык программирования в мире.