[python] Python을 사용한 웹 스크랩 핑 JavaScript 페이지

간단한 웹 스크레이퍼를 개발하려고합니다. HTML 코드없이 텍스트를 추출하고 싶습니다. 실제로이 목표를 달성했지만 JavaScript 가로 드 된 일부 페이지에서는 좋은 결과를 얻지 못했습니다.

예를 들어, 일부 JavaScript 코드가 텍스트를 추가하면 텍스트를 볼 수 없습니다.

response = urllib2.urlopen(request)

JavaScript가 클라이언트에서 실행되기 때문에 추가 된 텍스트없이 원본 텍스트를 얻습니다.

그래서이 문제를 해결할 아이디어를 찾고 있습니다.



답변

2017 년 12 월 30 일 수정 :이 답변은 Google 검색의 최상위 결과에 표시되므로 업데이트하기로 결정했습니다. 오래된 대답은 여전히 ​​끝났습니다.

dryscape는 더 이상 유지되지 않으며 라이브러리 dryscape 개발자는 Python 2 만 권장합니다. 나는 Phantom JS와 함께 Selenium의 python 라이브러리를 웹 드라이버로 사용하여 빠르고 쉽게 작업을 수행하는 것을 발견했습니다.

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>

자바 스크립트가 없으면 다음 No javascript support과 같이 나타납니다.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>


답변

자바 스크립트로 생성 된 콘텐츠를 DOM에서 렌더링해야하므로 올바른 결과를 얻지 못했습니다. HTML 페이지를 가져올 때 자바 스크립트 DOM에 의해 수정되지 않은 초기를 가져옵니다.

따라서 페이지를 크롤링하기 전에 자바 스크립트 컨텐츠를 렌더링해야합니다.

이 스레드에서 셀레늄이 이미 여러 번 언급되었으므로 (그리고 때때로 느리게 진행되는 경우도 언급되었으므로) 가능한 두 가지 다른 솔루션을 나열합니다.


해결 방법 1 : 이것은 Scrapy를 사용하여 자바 스크립트로 생성 된 콘텐츠를 크롤링하는 방법대한 매우 유용한 자습서 입니다.

우리가 필요한 것 :

  1. 기계에 Docker가 설치되었습니다. 이것은 OS 독립적 인 플랫폼을 사용하므로이 시점까지 다른 솔루션에 비해 장점입니다.

  2. 해당 OS에 대해 나열된 지침에 따라 Splash를 설치 하십시오.
    스플래시 문서에서 인용 :

    Splash는 자바 스크립트 렌더링 서비스입니다. Twisted 및 QT5를 사용하여 Python 3에서 구현 된 HTTP API를 갖춘 경량 웹 브라우저입니다.

    기본적으로 Splash를 사용하여 Javascript로 생성 된 컨텐츠를 렌더링합니다.

  3. 스플래시 서버를 실행하십시오 sudo docker run -p 8050:8050 scrapinghub/splash..

  4. scrapy-splash 플러그인을 설치하십시오 :pip install scrapy-splash

  5. 우리는 이미 (, 아니라면 만든 Scrapy 프로젝트가 있다고 가정 의 메이크업 하나하자 , 우리는 가이드를 따라 업데이트됩니다) settings.py:

    그런 다음 귀찮은 프로젝트로 이동하여 settings.py다음 미들웨어를 설정하십시오.

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

    Splash 서버의 URL (Win 또는 OSX를 사용하는 경우 도커 시스템의 URL이어야합니다 . 호스트에서 Docker 컨테이너의 IP 주소를 얻는 방법은 무엇입니까? ) :

    SPLASH_URL = 'http://localhost:8050'

    마지막으로 다음 값도 설정해야합니다.

    DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
    HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'
    
  6. 마지막으로 다음을 사용할 수 있습니다 SplashRequest.

    일반 스파이더에는 URL을 여는 데 사용할 수있는 Request 객체가 있습니다. 열려는 페이지에 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로 렌더링하고 callback (parse) 메서드에서 사용할 수있는 응답을 반환합니다.


해결 방법 2 : 이 실험을 지금 바로 호출 해 봅시다 (2018 년 5 월) …
이 솔루션은 현재 Python 버전 3.6 에만 해당됩니다.

요청 모듈 을 알고 있습니까?
이제 웹 크롤링 작은 형제가 있습니다 : 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.


답변

아마도 셀레늄 이 그것을 할 수 있습니다.

from selenium import webdriver
import time

driver = webdriver.Firefox()
driver.get(url)
time.sleep(5)
htmlSource = driver.page_source


답변

Requests이전에 파이썬 에서 모듈을 사용한 적이 있다면 최근에 개발자 Requests-HTML가 JavaScript를 렌더링 할 수 있는 새로운 모듈을 만들었습니다 .

https://html.python-requests.org/ 를 방문 하여이 모듈에 대해 자세히 알아 보거나 JavaScript 렌더링에 관심이있는 경우 https://html.python-requests.org/?#javascript 를 방문 하십시오. -지원 모듈을 사용하여 Python을 사용하여 JavaScript를 렌더링하는 방법을 직접 학습합니다.

기본적으로 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 동영상을 시청합니다.


답변

이것은 훌륭한 블로그 게시물 에서 가져온 좋은 솔루션 인 것 같습니다.

import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4.QtWebKit import *
from lxml import html

#Take this class for granted.Just use result of rendering.
class Render(QWebPage):
  def __init__(self, url):
    self.app = QApplication(sys.argv)
    QWebPage.__init__(self)
    self.loadFinished.connect(self._loadFinished)
    self.mainFrame().load(QUrl(url))
    self.app.exec_()

  def _loadFinished(self, result):
    self.frame = self.mainFrame()
    self.app.quit()

url = 'http://pycoders.com/archive/'
r = Render(url)
result = r.frame.toHtml()
# This step is important.Converting QString to Ascii for lxml to process

# The following returns an lxml element tree
archive_links = html.fromstring(str(result.toAscii()))
print archive_links

# The following returns an array containing the URLs
raw_links = archive_links.xpath('//div[@class="campaign"]/a/@href')
print raw_links


답변

실제로 찾고있는 데이터는 기본 페이지의 일부 자바 스크립트에서 호출 한 보조 URL을 통해 액세스 할 수있는 것처럼 들립니다.

서버에서 자바 스크립트를 실행하여이 문제를 처리 할 수는 있지만 Firefox를 사용하여 페이지를로드하고 Charles 또는 Firebug 와 같은 도구를 사용하여 해당 보조 URL이 무엇인지 정확히 식별 하는 간단한 방법이 있습니다 . 그런 다음 관심있는 데이터에 대해 해당 URL을 직접 쿼리하면됩니다.


답변

Selenium은 JS 및 Ajax 컨텐츠를 스크랩하는 데 가장 적합합니다.

Python을 사용하여 웹에서 데이터추출하려면 이 기사를 확인하십시오.

$ pip install selenium

그런 다음 Chrome 웹 드라이버를 다운로드하십시오.

from selenium import webdriver

browser = webdriver.Chrome()

browser.get("https://www.python.org/")

nav = browser.find_element_by_id("mainnav")

print(nav.text)

쉬운가요?