Почему я получаю строку emty из Xpath

#python #web-scraping #xpath

Вопрос:

Пожалуйста, помогите мне понять, почему мой код возвращает пустую строку вместо текста span. Я новичок в этом, я получаю ответ 200, сделал те же шаги, что и с другим сайтом (он там работает), но в этом случае не без ошибок в конце. Это html — код, который я анализирую, мне нужно получить строку «Cessna Citation CJ3».

 <div class="acTitle" style="margin-bottom: 4px;"> 
  <i class="fa fa-plane"></i> <span ng-bind="flight.ac.title" class="ng- binding">Cessna Citation CJ3</span>
</div>
 

Вот мой код:

 import requests
import lxml.html

url = 'https://flyeasy.co/opapi/-fe3-dt1--ht2--ht3--ht4-ctp:magellanjets_list:-/' 
        '578526bdf6c494c11477ab06/'

headers = {
    'user-agent':  'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0'
}

def parse_data(url, headers):
    titles = []
    try:
        response = requests.get(url, headers=headers)
        print(response)
    except:
        return
    tree = lxml.html.document_fromstring(response.text)
    for item in tree.xpath('//*[contains(@class, "acTitle")]'):
        title = item.xpath(".//span/text()")
        print(title)
        titles.append(title)
        print(titles)
        print(len(titles))


parse_data(url, headers)
 

Комментарии:

1. Глупый вопрос, но вы цитируете HTML, который вы видели в своем браузере, или фактический контент в response.text нем ? Это не всегда одно и то же-браузер часто выполняет исправления DOM во время синтаксического анализа.

2. Как бы то ни было, используя примеры данных в верхней части вашего вопроса, ваш код, похоже, работает нормально (хотя обратите внимание, что xpath метод всегда возвращает список, а не строку, поэтому при настройке title вы можете принять это во внимание).

3. @Копатыч, как я уже сказал, ремонт ДОМА. HTML имеет несколько способов написания, поэтому иногда браузер нормализует содержимое по мере его загрузки, чтобы механизм рендеринга мог принимать определенную интерпретацию вместо необходимости поддерживать несколько возможностей. Вы должны быть в состоянии определить, так ли это здесь, посмотрев на фактический текст ответа и посмотрев, отличается ли соответствующий контент.

4. @Копатыч, …также стоит проверить response.text , не происходит ли что-то вроде загрузки реального контента с помощью javascript, которого вообще нет в первоначальном ответе на простой HTML.

5. @Копатыч, …в общем, если вам нужен поддерживаемый , поддерживаемый способ очистки данных сайта, вам следует попытаться получить API, который должным образом поддерживается людьми, которые его запускают. Если они не хотят, чтобы вы очищали, у них есть неопределенное количество способов сломать ваш скребок (и попытка выяснить, какой из них они используют в любой конкретный день, не подходит для переполнения стека, учитывая почти неопределенный объем вопроса и вероятность того, что «правильный» ответ внезапно станет неправильным, как только будет обновлена серверная сторона).

Ответ №1:

Содержание этого сайта сильно динамично. Он недоступен в источнике страницы. При печати response.text или проверке вручную с помощью (ctrl u) вы не увидите желаемое содержимое.

Однако существует доступный api, который содержит всю информацию, которую вы видите на этой странице, включая лениво загруженные. Учитывая, что следующий сценарий должен предоставить вам все заголовки с этой страницы.

При выполнении сценария может потребоваться значительное время для возврата результатов, поэтому подождите, пока вы не увидите вывод в консоли.

 import requests

api_link = "https://flyeasy.co/api/search"
start_link = 'https://flyeasy.co/opapi/-fe3-dt1--ht2--ht3--ht4-ctp:magellanjets_list:-/578526bdf6c494c11477ab06/'

opid = start_link.split("/")[-2]

params = {"opIds":[f"{opid}"],"trip":"offers","source":"eq","promoteOpIds":"all"}

with requests.Session() as s:
    s.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36'
    s.headers['Referer'] = start_link
    res = s.post(api_link,json=params)
    for item in res.json()['flights']['departing']:
        print(item['ac']['title'])
 

Комментарии:

1. Это работает, но теперь я понимаю, что «мои силы слабы», и мне нужно научиться гораздо большему, чтобы анализировать такие сайты, потому что я не понимаю, как получить параметры из вашего кода. Большое вам спасибо за ваше время и ответ!

2. Кстати, есть ли что-нибудь, чтобы понять, что сайт настолько «тяжелый» для разбора? Может быть, что-то в URL или в коде сайта в браузере?

3. Поскольку необходимый контент этого сайта загружается позже, его нет в источнике страницы, поэтому вряд ли есть какой-либо другой вариант, кроме того, как я уже показал, если вы придерживаетесь модуля запросов. Тем не менее, вы все равно можете получить контент, используя селекторы, которые вы пробовали выше, если вы выберете селен. Спасибо.

4. Спасибо тебе, а не мне! У меня очень быстрый Интернет, поэтому неясно, короткое время загрузки страницы или нет. Я думал, что «/opapi/» или что-то в этом роде-это возможность проверить, что URL-адрес не «простой».

5. Это то, что вы можете сделать, чтобы получить названия с помощью selenium.