Очистка скрытых данных [окно .__ WEB_CONTEXT __ =] ... предпочтительно с помощью Scrapy - PullRequest
0 голосов
/ 06 августа 2020

Я просматриваю tripadvisor. Моя проблема прямо сейчас состоит в том, чтобы очистить Hotelstars (не средний пользовательский рейтинг [пузыри], а рейтинг класса отеля) данного отеля, и позже я столкнусь с проблемой, когда отзывы скрыты за «читать дальше». https://www.tripadvisor.com.ph/Hotel_Review-g8762949-d1085145-Reviews-El_Rio_y_Mar_Resort-San_Jose_Coron_Busuanga_Island_Palawan_Province_Mimaropa.html К счастью, я знаю, где данные, где их найти. На странице с этим тегом:

<script window.__WEB_CONTEXT={pageManifest:{"assets":[.... 
....
</script>

ищите здесь https://pastebin.com/Ww3ugxFR по запросу «Вид был фантастическим c !!» (пример скрытого текста) или «звездочка»: для Hotelstars.

Я хочу узнать, как получить доступ к этому тегу.

Вот мой пример того, как это не работает. Мне нужно узнать, как указать селектору CSS (или другому инструменту), как обращаться к этой спецификации c и как извлекать из нее данные. Здесь, в этом примере, я просто загружаю ответ и выполняю простой поиск по шаблону. Я предполагаю, что можно также загрузить его с помощью Json и извлечь оттуда, но я еще не уверен с Json. :

hotel_CONTEXT = response.css("script text=window.__WEB_CONTEXT ::attr(pageManifest)).extract()

pattern_hotelstar = re.compile(r'star":\["\d')
matches_hotelstar = pattern_hotelstar.findall(hotel_CONTEXT)
Hotel_stars = str(matches_hotelstar).split('"')[2].split("'")[0]

Очевидно, что я хочу достичь, возможно с BeautifulSoup ( Очистка веб-сайта с данными, скрытыми в разделе «Подробнее» ... однако при попытке репликации я получил ошибки с json), но в целом я бы предпочел решение с помощью Scrapy.

Андрей Кеселий предоставил отличное решение моей проблемы! Его код работает так хорошо, что я хочу полностью его понять! Вот то, что я думаю, чтобы понять из кода, и где я просто не понимаю его колдовства;):

data = re.search(r'window\.__WEB_CONTEXT__=(.*?});', html_text).group(1)

Андрей ищет весь html_text шаблон, который начинается с "window .__ WEB ..." ", расширяет шаблон на все символы (.), любое количество раз (*) не жадным образом (?) и заканчивается на"; ". Я не понимаю, почему существует группа захвата с} init и почему} не было просто помещено в конец, учитывая, что сценарий заканчивается на}; (как Андрей это узнал? Это общий шаблон для них или он распечатал всю страницу и посмотрел?). Я также не понимаю, почему это должно быть не жадное. Группа (1) выбрала все в пределах первого окна выхода парантезы. WEB_CONTEXT = out. Я предполагаю, что это как-то связано с загрузкой результата с помощью json. То же самое касается

data = data.replace('pageManifest', '"pageManifest"')   

Затем Андрей создает функцию под названием traverse, которая позже будет заполнена выводом данных. В операторе if Андрей проверяет, является ли ввод словарем. На следующем этапе Андрей перебирает ключ (k) и значение (v) словаря. Если k == "проверяет", он возвращает значение. Если не "выход из функции" ?? Я тоже потерялся с elif и проверкой, является ли val списком ... В общем, каков результат v функции? Как мне изменить функцию, чтобы включить больше словарей для прокрутки, поскольку else уже занято этим yield from.

def traverse(val):
if isinstance(val, dict):
    for k, v in val.items():
        if k == 'reviews':
            yield v
        else:
            yield from traverse(v)
elif isinstance(val, list):
    for v in val:
        yield from traverse(v)
 

Здесь Андрей просматривает обход (данные) (словарь, верно?). Поскольку у нас есть несколько обзоров на этой странице. Во вложенном l oop Андрей дает каждому словарю в рамках одного обзора имя r и с помощью dictonary_name ["key"] получает значение, которое хранится. Я прав?

for reviews in traverse(data):
  for r in reviews:
    print(r['userProfile']['displayName'])
    print(r['title'])
    print(r['text'])
    print('Rating:', r['rating'])
    print('-' * 80)

Простите за все эти ладьи ie вопросы.

Ответы [ 2 ]

1 голос
/ 06 августа 2020

Этот скрипт распечатает все обзоры и рейтинг обзора, найденные на странице:

import re
import json
import requests


url = 'https://www.tripadvisor.com.ph/Hotel_Review-g8762949-d1085145-Reviews-El_Rio_y_Mar_Resort-San_Jose_Coron_Busuanga_Island_Palawan_Province_Mimaropa.html'
html_text = requests.get(url).text

data = re.search(r'window\.__WEB_CONTEXT__=(.*?});', html_text).group(1)
data = data.replace('pageManifest', '"pageManifest"')
data = json.loads(data)

# uncomment this to print all data:
# print(json.dumps(data, indent=4))

def traverse(val):
    if isinstance(val, dict):
        for k, v in val.items():
            if k == 'reviews':
                yield v
            else:
                yield from traverse(v)
    elif isinstance(val, list):
        for v in val:
            yield from traverse(v)

for reviews in traverse(data):
    for r in reviews:
        print(r['userProfile']['displayName'])
        print(r['title'])
        print(r['text'])
        print('Rating:', r['rating'])
        print('-' * 80)

Распечатывает:

BBDoll619
Just WOW!!
Okay, I didn't know this resort would be mainly couples and honeymooners as I went with 2 friends. We weren't uncomfortable though and met lots of nice people from across the globe and 1 couple from the US. This resort can only be reached by boat, so it is very secluded. We stayed in bungalow #2. It was rustic, but beautiful and right on the beach. Everyone who worked in the resort was friendly and very accommodating. We ate most meals at the resort which was pretty good. We had happy hour at the pier bar every day which was from 4-7pm. They had half off certain drinks and food specials. It was very nice relaxing, enjoying a great drink and watching the sunset. You can snorkel right in front of the resort which was so cool! We snorkeled for 2 hours!! The best is right by the floating bungalows where they did massages. Speaking of massages....OMG! It was heaven!! Very affordable and different. When you lie face down, you look into a cut out in the floor, so you can view the water and fish swimming by. I loved it!! We did an island hopping tour and it was not an issue coming from this resort. When we got into Coron town and passed by all the hotels in that area, we were so glad and thankful we chose El Rio Y Mar. Coron Town is very dirty, dusty, full of young backpackers and the hotels look subpar. It's fine if you're on a budget. I get it, but us girls/mom/friends wanted to treat ourselves. That we did! One day we went on a guided hike to the top of a closeby mountain. The view was fantastic!! I highly recommend this resort and would definitely return.
Rating: 5
--------------------------------------------------------------------------------
MaricrisAndPiotr
Amazing staff
The best customer experience we ever had! the school of fishes within the resort are amazing, very quite, very clean and well maintained rooms and outdoor surroundings. Our island trip organized by them is one of the best experience we had in our Coron trip. 
Kudos to El Rio highly recommended
Rating: 5
--------------------------------------------------------------------------------

...and so on.
0 голосов
/ 06 августа 2020

Вы упомянули scrapy в своем вопросе, поэтому добавление решения с использованием этого и chomp js.

scrapy shell https://www.tripadvisor.com.ph/Hotel_Review-g8762949-d1085145-Reviews-El_Rio_y_Mar_Resort-San_Jose_Coron_Busuanga_Island_Palawan_Province_Mimaropa.html

>>>import chompjs
>>>resp=response.xpath("//script[contains(.,'requests')]/text()").extract_first() 
>>>data=chompjs.parse_js_object(resp)

Для анализа данных решение Андрея работает отлично. Вы можете добавить определение в обычный Calss Spider с небольшими настройками

import chompjs
import scrapy
Class SomeSpider (scrapy.Spider)
--------Code here------------
--------Code here------------
 def traverse(self,val):
   if isinstance(val, dict):
     for k, v in val.items():
       if k == 'reviews':
         yield v
       else:
         yield from self.traverse(v)
   elif isinstance(val, list):
     for v in val:
        yield from self.traverse(v)

   

 def parse(self, response)
    
  resp=response.xpath("//script[contains(.,'requests')]/text()").extract_first()
  data=chompjs.parse_js_object(resp)
  for reviews in self.traverse(data):
   for r in reviews:
    yield {---code here---
           ---code here---
    }
...