Вопрос-Ответ

How can I scrape a page with dynamic content (created by JavaScript) in Python?

Как я могу очистить страницу с динамическим содержимым (созданным JavaScript) в Python?

Я пытаюсь разработать простой веб-скребок. Я хочу извлекать обычный текст без HTML-разметки. Мой код работает с обычным (статическим) HTML, но не тогда, когда содержимое генерируется JavaScript, встроенным в страницу.

В частности, когда я использую urllib2.urlopen(request) для чтения содержимого страницы, оно не показывает ничего, что могло бы быть добавлено кодом JavaScript, потому что этот код нигде не выполняется. Обычно это запускается веб-браузером, но это не является частью моей программы.

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


Смотрите также можно ли использовать scrapy для очистки динамического содержимого с веб-сайтов, использующих AJAX? ответы, относящиеся к Scrapy.

Переведено автоматически
Ответ 1

РЕДАКТИРОВАТЬ сентябрь 2021: phantomjs также больше не поддерживается

РЕДАКТИРОВАТЬ 30 / Dec / 2017: этот ответ отображается в лучших результатах поиска Google, поэтому я решил его обновить. Старый ответ все еще находится в конце.

dryscape больше не поддерживается, и разработчики dryscape рекомендуют использовать только библиотеку Python 2. Я обнаружил, что использование библиотеки python от Selenium с Phantom JS в качестве веб-драйвера достаточно быстро и просто для выполнения работы.

После установки Phantom JS убедитесь, что phantomjs двоичный файл доступен по текущему пути:

phantomjs --version
# result:
2.1.1

# Пример
Чтобы привести пример, я создал пример страницы со следующим HTML-кодом. (ссылка):

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Javascript scraping test</title>
</head>
<body>
<p id='intro-text'>No javascript support</p>
<script>
document.getElementById('intro-text').innerHTML = 'Yay! Supports javascript';
</script>
</body>
</html>

без javascript написано: No javascript support и с помощью javascript: Yay! Supports javascript

# Очистка без поддержки JS:

import requests
from bs4 import BeautifulSoup
response = requests.get(my_url)
soup = BeautifulSoup(response.text)
soup.find(id="intro-text")
# Result:
<p id="intro-text">No javascript support</p>

# Очистка с поддержкой JS:

from selenium import webdriver
driver = webdriver.PhantomJS()
driver.get(my_url)
p_element = driver.find_element_by_id(id_='intro-text')
print(p_element.text)
# result:
'Yay! Supports javascript'

Вы также можете использовать библиотеку Python dryscrape для очистки веб-сайтов, управляемых javascript.

# Очистка с поддержкой JS:

import dryscrape
from bs4 import BeautifulSoup
session = dryscrape.Session()
session.visit(my_url)
response = session.body()
soup = BeautifulSoup(response)
soup.find(id="intro-text")
# Result:
<p id="intro-text">Yay! Supports javascript</p>
Ответ 2

Мы не получаем правильных результатов, потому что любое содержимое, сгенерированное javascript, должно быть отображено в DOM. Когда мы извлекаем HTML-страницу, мы извлекаем начальный, неизмененный javascript, DOM.

Поэтому нам нужно отобразить содержимое javascript перед обходом страницы.

Поскольку selenium уже много раз упоминается в этой теме (и также упоминалось, насколько медленно он иногда работает), я перечислю два других возможных решения.


Решение 1: Это очень хороший учебник о том, как использовать Scrapy для обхода содержимого, сгенерированного javascript, и мы собираемся следовать именно этому.

Что нам понадобится:


  1. На нашем компьютере установленDocker. До этого момента это было плюсом по сравнению с другими решениями, поскольку оно использует платформу, независимую от операционной системы.


  2. Установите Splash, следуя инструкции, указанной для нашей соответствующей ОС.
    Цитирую документацию splash:



    Splash - это служба рендеринга javascript. Это легкий веб-браузер с HTTP API, реализованный на Python 3 с использованием Twisted и QT5.



    По сути, мы собираемся использовать Splash для рендеринга содержимого, сгенерированного Javascript.


  3. Запустите сервер splash: sudo docker run -p 8050:8050 scrapinghub/splash.


  4. Установите плагин scrapy-splash: pip install scrapy-splash


  5. Предполагая, что у нас уже есть созданный Scrapy-проект (если нет, давайте создадим один), мы будем следовать руководству и обновлять settings.py:



    Затем перейдите в свой проект scrapy settings.py и установите эти промежуточные программы:


    DOWNLOADER_MIDDLEWARES = {
    'scrapy_splash.SplashCookiesMiddleware': 723,
    'scrapy_splash.SplashMiddleware': 725,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
    }

    URL сервера Splash (если вы используете Win или OSX, это должен быть URL компьютера docker: Как получить IP-адрес контейнера Docker от хоста?):


    SPLASH_URL = 'http://localhost:8050'

    И, наконец, вам также нужно установить эти значения:


    DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
    HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'


  6. Наконец, мы можем использовать SplashRequest:



    В обычном spider у вас есть объекты запроса, которые вы можете использовать для открытия URL-адресов. Если страница, которую вы хотите открыть, содержит данные, сгенерированные JS, вы должны использовать SplashRequest (или SplashFormRequest) для рендеринга страницы. Вот простой пример.:


    class MySpider(scrapy.Spider):
    name = "jsscraper"
    start_urls = ["http://quotes.toscrape.com/js/"]

    def start_requests(self):
    for url in self.start_urls:
    yield SplashRequest(
    url=url, callback=self.parse, endpoint='render.html'
    )

    def parse(self, response):
    for q in response.css("div.quote"):
    quote = QuoteItem()
    quote["author"] = q.css(".author::text").extract_first()
    quote["quote"] = q.css(".text::text").extract_first()
    yield quote

    SplashRequest отображает URL-адрес в виде html и возвращает ответ, который вы можете использовать в методе обратного вызова (parse).




Решение 2: На данный момент (май 2018 г.) давайте назовем это экспериментальным...

Это решение предназначено только для Python версии 3.6 (на данный момент).

Вы знаете модуль requests (а кто его не знает)?
Теперь у него есть младший брат для обхода веб-страниц: requests-HTML:


Эта библиотека предназначена для того, чтобы сделать синтаксический анализ HTML (например, очистить веб) максимально простым и интуитивно понятным.



  1. Запросы на установку-html: pipenv install requests-html


  2. Сделайте запрос к URL страницы:


    from requests_html import HTMLSession

    session = HTMLSession()
    r = session.get(a_page_url)

  3. Визуализируйте ответ, чтобы получить сгенерированные Javascript биты:


    r.html.render()

Наконец, модуль, похоже, предлагает возможности очистки.

В качестве альтернативы мы можем попробовать хорошо документированный способ использования BeautifulSoup с r.html объектом, который мы только что визуализировали.

Ответ 3

Возможно, selenium сможет это сделать.

from selenium import webdriver
import time

driver = webdriver.Firefox()
driver.get(url)
time.sleep(5)
htmlSource = driver.page_source
Ответ 4

Если вы когда-либо раньше использовали Requests модуль для python, я недавно узнал, что разработчик создал новый модуль под названием Requests-HTML который теперь также имеет возможность отображать JavaScript.

Вы также можете посетить https://html.python-requests.org / чтобы узнать больше об этом модуле, или, если вас интересует только рендеринг JavaScript, вы можете посетить https://html.python-requests.org/?#javascript-support чтобы непосредственно узнать, как использовать модуль для рендеринга JavaScript с помощью Python.

По сути, после правильной установки Requests-HTML модуля следующий пример, который показан по ссылке выше, показывает, как вы можете использовать этот модуль для очистки веб-сайта и визуализации JavaScript, содержащегося на веб-сайте:

from requests_html import HTMLSession
session = HTMLSession()

r = session.get('http://python-requests.org/')

r.html.render()

r.html.search('Python 2 will retire in only {months} months!')['months']

'<time>25</time>' #This is the result.

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

python