หน้าจาวาสคริปต์การขูดเว็บด้วย Python


178

ฉันพยายามที่จะพัฒนามีดโกนเว็บอย่างง่าย ฉันต้องการแยกข้อความโดยไม่มีรหัส HTML ในความเป็นจริงฉันบรรลุเป้าหมายนี้ แต่ฉันเห็นว่าในบางหน้าเว็บที่โหลด JavaScript ฉันไม่ได้รับผลลัพธ์ที่ดี

ตัวอย่างเช่นหากรหัส JavaScript บางตัวเพิ่มข้อความฉันไม่เห็นเพราะเมื่อฉันโทร

response = urllib2.urlopen(request)

ฉันได้รับข้อความต้นฉบับโดยไม่มีข้อความเพิ่ม (เพราะมีการใช้งาน JavaScript ในไคลเอนต์)

ดังนั้นฉันกำลังมองหาแนวคิดเพื่อแก้ไขปัญหานี้


2
ดูเหมือนว่าคุณอาจต้องการอะไรที่หนักกว่าลองซีลีเนียมหรือ Watir
Wim

2
ฉันทำสิ่งนี้สำเร็จใน Java (ฉันใช้ Cobra toolkit lobobrowser.org/cobra.jsp ) เนื่องจากคุณต้องการแฮ็คใน python (เป็นตัวเลือกที่ดีเสมอ) ฉันแนะนำตัวเลือกเหล่านี้สองตัวเลือก: - packtpub.com/article/ web-scraping-with-python-part-2 - blog.databigbang.com/web-scraping-ajax-and-javascript-sites
bpgergo

คำตอบ:


203

แก้ไข 30 / Dec / 2017: คำตอบนี้ปรากฏในผลลัพธ์สูงสุดของการค้นหาของ Google ดังนั้นฉันตัดสินใจที่จะอัปเดต คำตอบเก่ายังคงอยู่ในตอนท้าย

dryscape ไม่ได้รับการดูแลอีกต่อไปและผู้พัฒนา dryscape ของห้องสมุดแนะนำคือ Python 2 เท่านั้น ฉันพบว่าใช้ห้องสมุดหลามของ 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>

16
น่าเศร้าที่ไม่มี Windows รองรับ
Expenzor

1
ทางเลือกใด ๆ สำหรับพวกเราที่เขียนโปรแกรมใน Windows?
Hoshiko86

2
@Expenzorฉันกำลังทำงานบน windows PhantomJS ทำงานได้ดี
Aakash Choubey

17
น่าสังเกตว่า PhantomJS ถูกยกเลิกและไม่อยู่ภายใต้การพัฒนาที่ใช้งานได้อีกต่อไปในแง่ของ Chrome ในขณะนี้ที่สนับสนุนการไม่ใช้งาน แนะนำให้ใช้หัวโครเมี่ยม / Firefox
sytech

3
มันเป็นทั้งซีลีเนียมที่รองรับและ PhantomJS เอง github.com/ariya/phantomjs/issues/15344
sytech

73

เราไม่ได้รับผลลัพธ์ที่ถูกต้องเนื่องจากจำเป็นต้องสร้างเนื้อหาจาวาสคริปต์ใน DOM เมื่อเราดึงข้อมูลหน้า HTML เราจะดึงข้อมูลเริ่มต้นซึ่งไม่มีการแก้ไขโดย javascript, DOM

ดังนั้นเราจำเป็นต้องแสดงเนื้อหาจาวาสคริปต์ก่อนที่จะรวบรวมข้อมูลหน้าเว็บ

เนื่องจากมีการกล่าวถึงซีลีเนียมหลายต่อหลายครั้งในหัวข้อนี้ (และได้รับการกล่าวถึงช้าเพียงใด) ฉันจะแสดงวิธีแก้ปัญหาที่เป็นไปได้อีกสองรายการ


โซลูชันที่ 1:นี่คือการสอนที่ดีมากเกี่ยวกับวิธีการใช้ Scrapy เพื่อรวบรวมข้อมูลจาวาสคริปต์ที่สร้างเนื้อหาและเราจะทำตามนั้น

สิ่งที่เราต้องการ:

  1. นักเทียบท่าติดตั้งในเครื่องของเรา นี่คือข้อดีมากกว่าโซลูชันอื่น ๆ จนถึงจุดนี้เนื่องจากใช้แพลตฟอร์ม OS อิสระ

  2. ติดตั้ง Splashตามคำแนะนำที่ระบุไว้สำหรับระบบปฏิบัติการที่สอดคล้องกันของเรา
    การอ้างอิงจากเอกสารสแปลช:

    Splash เป็นบริการการแสดงผล javascript มันเป็นเว็บเบราว์เซอร์ที่มีน้ำหนักเบาพร้อม HTTP API ที่ใช้งานใน Python 3 โดยใช้ Twisted และ QT5

    โดยพื้นฐานแล้วเราจะใช้ 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,
    }

    URL ของเซิร์ฟเวอร์ Splash (หากคุณใช้ Win หรือ OSX ควรเป็น URL ของเครื่องเทียบท่า: วิธีรับที่อยู่ IP ของคอนเทนเนอร์ Docker จากโฮสต์หรือไม่ ):

    SPLASH_URL = 'http://localhost:8050'

    และในที่สุดคุณก็จำเป็นต้องตั้งค่าเหล่านี้ด้วย:

    DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
    HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'
  6. สุดท้ายเราสามารถใช้SplashRequest:

    ในสไปเดอร์ปกติคุณมีวัตถุขอซึ่งคุณสามารถใช้เพื่อเปิด 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 และส่งคืนการตอบกลับซึ่งคุณสามารถใช้ในวิธีการโทรกลับ (แยกวิเคราะห์)


โซลูชันที่ 2:เรียกการทดลองนี้ในขณะนี้ (พฤษภาคม 2018) ...
โซลูชันนี้ใช้สำหรับ Python รุ่น 3.6เท่านั้น (ในขณะนี้)

คุณรู้โมดูลคำขอ (คนที่ไม่ได้)?
ตอนนี้มันมีเว็บเล็ก ๆ น้อย ๆ ในการรวบรวมข้อมูลการร้องขอ : 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วัตถุที่เราเพิ่งแสดงผล


คุณสามารถขยายวิธีรับเนื้อหา HTML แบบเต็มโดยโหลด JS bits หลังจากโทร. render () ฉันติดอยู่หลังจากนั้น ฉันไม่เห็น iframe ทั้งหมดที่ถูกแทรกเข้าสู่หน้าเว็บตามปกติจาก JavaScript ในr.html.htmlวัตถุ
anon58192932

@ anon58192932 เนื่องจากในขณะนี้เป็นวิธีการทดลองและฉันไม่รู้ว่าสิ่งที่คุณพยายามที่จะบรรลุผลฉันไม่สามารถแนะนำอะไรได้จริงๆ ... คุณสามารถสร้างคำถามใหม่ได้ที่นี่หากคุณยังไม่ได้ ยังแก้ปัญหาได้
John Moutafis

2
ฉันได้รับข้อผิดพลาดนี้: RuntimeError: ไม่สามารถใช้ HTMLSession ภายในเหตุการณ์ลูปที่มีอยู่ ใช้ AsyncHTMLSession แทน
HuckIt

1
@HuckIt ดูเหมือนว่าจะเป็นปัญหาที่ทราบกันดี: github.com/psf/requests-html/issues/140
John Moutafis

47

บางทีซีลีเนียมสามารถทำมันได้

from selenium import webdriver
import time

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

3
ซีลีเนียมหนักมากสำหรับสิ่งนี้ซึ่งช้าและไม่จำเป็นโดยไม่ต้องใช้หัวเบราว์เซอร์ถ้าคุณไม่ใช้ PhantomJS แต่สิ่งนี้จะใช้ได้
Joshua Hedges

@JoshuaHedges คุณสามารถเรียกใช้เบราว์เซอร์มาตรฐานอื่น ๆ เพิ่มเติมในโหมดหัวขาด
reynoldsnlp

22

หากคุณเคยใช้Requestsโมดูลสำหรับ python มาก่อนฉันเพิ่งค้นพบว่านักพัฒนาสร้างโมดูลใหม่ที่เรียกว่าRequests-HTMLซึ่งตอนนี้ก็มีความสามารถในการแสดง JavaScript

นอกจากนี้คุณยังสามารถเยี่ยมชมhttps://html.python-requests.org/เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับโมดูลนี้หรือหากคุณสนใจที่จะแสดง JavaScript เท่านั้นคุณสามารถเยี่ยมชมhttps://html.python-requests.org/?#javascript - สนับสนุนการเรียนรู้วิธีใช้โมดูลเพื่อแสดงผล 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 ซึ่งสาธิตวิธีการทำงานของโมดูล


3
ควรทราบว่าโมดูลนี้รองรับ Python 3.6 เท่านั้น
nat5142

1
ฉันได้รับข้อผิดพลาดนี้: SSLError: HTTPSConnectionPool (โฮสต์ = 'docs.python-requests.org', พอร์ต = 443): มีการลองใหม่เกินจำนวนสูงสุดด้วย url: / (เกิดจาก SSLError (SSLError (1, '[SSL: TLSV1_ALERT_INTERNAL_ERROR]) ข้อผิดพลาดภายใน (_ssl.c: 1045) ')))
HuckIt

@HuckIt appologies ฉันไม่คุ้นเคยกับข้อผิดพลาดนั้น แต่ดูเหมือนว่าข้อผิดพลาดเว็บไซต์ที่คุณพยายามเข้าถึงอาจมีปัญหา SSL certifaction ที่เกี่ยวข้อง ขออภัยนี่ไม่ใช่วิธีแก้ปัญหา แต่ฉันขอแนะนำให้คุณสร้างคำถามใหม่ที่นี่ใน stack overflow (หากยังไม่ได้รับการถาม) และอาจให้รายละเอียดเพิ่มเติมเช่น URL เว็บไซต์ที่คุณใช้และรหัสของคุณ
SShah

ดูเหมือนว่าจะใช้โครเมียมภายใต้ประทุน การทำงานที่ดีสำหรับฉันแม้ว่า
ซิด

14

นี่ดูเหมือนจะเป็นทางออกที่ดีเช่นกันซึ่งนำมาจากการโพสต์บล็อกที่ยอดเยี่ยม

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

12

ดูเหมือนว่าข้อมูลที่คุณกำลังมองหาสามารถเข้าถึงได้ผ่านทาง URL รองที่เรียกโดยจาวาสคริปต์บางอย่างในหน้าหลัก

ในขณะที่คุณสามารถลองใช้จาวาสคริปต์บนเซิร์ฟเวอร์เพื่อจัดการสิ่งนี้วิธีที่ง่ายกว่าคืออาจโหลดหน้าเว็บด้วย Firefox และใช้เครื่องมือเช่นCharlesหรือFirebugเพื่อระบุ URL รองที่แน่นอน จากนั้นคุณสามารถสอบถาม URL นั้นโดยตรงสำหรับข้อมูลที่คุณสนใจ


@Kris ในกรณีที่มีคนสะดุดและต้องการลองแทนสิ่งที่หนักหนากว่าซีลีเนียมนี่เป็นตัวอย่างสั้น ๆ นี่จะเปิดหน้ารายละเอียดชิ้นส่วนสำหรับน็อตหกเหลี่ยมบนเว็บไซต์ McMaster-Carr เนื้อหาเว็บไซต์ของพวกเขาส่วนใหญ่ถูกเรียกโดยใช้ Javascript และมีข้อมูลหน้าดั้งเดิมน้อยมาก หากคุณเปิดเครื่องมือนักพัฒนาเบราว์เซอร์ของคุณนำทางไปที่แท็บเครือข่ายและรีเฟรชหน้าคุณสามารถดูคำขอทั้งหมดที่ทำโดยหน้าและค้นหาข้อมูลที่เกี่ยวข้อง (ในกรณีนี้คือรายละเอียดส่วน html)
SweepingsDemon

นี่คือ URL อื่นที่พบในแท็บ Firefox devtool Network ซึ่งหากติดตามจะมี html สำหรับข้อมูลส่วนใหญ่และเปิดเผยพารามิเตอร์บางอย่างที่จำเป็นเพื่อนำทางไปยังข้อมูลส่วนอื่น ๆ ได้ง่ายขึ้นเพื่อการขูดได้ง่ายขึ้น ตัวอย่างนี้ไม่เป็นประโยชน์อย่างยิ่งเนื่องจากราคาถูกสร้างขึ้นโดยฟังก์ชัน Javascript อื่น แต่ควรทำหน้าที่ได้ดีพอที่จะแนะนำผู้ที่ต้องการทำตามคำแนะนำของสตีเฟ่น
SweepingsDemon

12

ซีลีเนียมนั้นดีที่สุดสำหรับการขูดเนื้อหา JS และ Ajax

ตรวจสอบบทความนี้เพื่อดึงข้อมูลจากเว็บโดยใช้ Python

$ pip install selenium

จากนั้นดาวน์โหลด Chrome webdriver

from selenium import webdriver

browser = webdriver.Chrome()

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

nav = browser.find_element_by_id("mainnav")

print(nav.text)

ง่ายใช่มั้ย


8

นอกจากนี้คุณยังสามารถเรียกใช้งานจาวาสคริปต์โดยใช้ webdriver

from selenium import webdriver

driver = webdriver.Firefox()
driver.get(url)
driver.execute_script('document.title')

หรือเก็บค่าไว้ในตัวแปร

result = driver.execute_script('var text = document.title ; return var')

หรือคุณสามารถใช้driver.titleคุณสมบัตินี้ได้
คอเรย์โกลด์เบิร์ก

8

โดยส่วนตัวแล้วฉันชอบที่จะใช้ scrapy และ selenium และ dockerizing ทั้งสองในภาชนะที่แยกต่างหาก วิธีนี้คุณสามารถติดตั้งได้ทั้งกับความยุ่งยากน้อยที่สุดและรวบรวมข้อมูลเว็บไซต์ทันสมัยที่เกือบทั้งหมดมีจาวาสคริปต์ในรูปแบบเดียวหรืออีกรูปแบบหนึ่ง นี่คือตัวอย่าง:

ใช้scrapy startprojectเพื่อสร้างมีดโกนของคุณและเขียนแมงมุมของคุณโครงกระดูกสามารถทำได้ง่ายอย่างนี้:

import scrapy


class MySpider(scrapy.Spider):
    name = 'my_spider'
    start_urls = ['https://somewhere.com']

    def start_requests(self):
        yield scrapy.Request(url=self.start_urls[0])


    def parse(self, response):

        # do stuff with results, scrape items etc.
        # now were just checking everything worked

        print(response.body)

ความมหัศจรรย์ที่แท้จริงเกิดขึ้นใน middlewares.py เขียนทับสองวิธีในมิดเดิลแวร์ของตัวดาวน์โหลด __init__และ process_requestด้วยวิธีต่อไปนี้:

# import some additional modules that we need
import os
from copy import deepcopy
from time import sleep

from scrapy import signals
from scrapy.http import HtmlResponse
from selenium import webdriver

class SampleProjectDownloaderMiddleware(object):

def __init__(self):
    SELENIUM_LOCATION = os.environ.get('SELENIUM_LOCATION', 'NOT_HERE')
    SELENIUM_URL = f'http://{SELENIUM_LOCATION}:4444/wd/hub'
    chrome_options = webdriver.ChromeOptions()

    # chrome_options.add_experimental_option("mobileEmulation", mobile_emulation)
    self.driver = webdriver.Remote(command_executor=SELENIUM_URL,
                                   desired_capabilities=chrome_options.to_capabilities())


def process_request(self, request, spider):

    self.driver.get(request.url)

    # sleep a bit so the page has time to load
    # or monitor items on page to continue as soon as page ready
    sleep(4)

    # if you need to manipulate the page content like clicking and scrolling, you do it here
    # self.driver.find_element_by_css_selector('.my-class').click()

    # you only need the now properly and completely rendered html from your page to get results
    body = deepcopy(self.driver.page_source)

    # copy the current url in case of redirects
    url = deepcopy(self.driver.current_url)

    return HtmlResponse(url, body=body, encoding='utf-8', request=request)

อย่าลืมที่จะเปิดใช้งาน middlware นี้โดยไม่ใส่เครื่องหมายในบรรทัดถัดไปในไฟล์ settings.py:

DOWNLOADER_MIDDLEWARES = {
'sample_project.middlewares.SampleProjectDownloaderMiddleware': 543,}

ถัดไปสำหรับการเชื่อมต่อ สร้างของคุณDockerfileจากอิมเมจน้ำหนักเบา (ฉันใช้ python Alpine ที่นี่) คัดลอกไดเรกทอรีโครงการของคุณไปยังข้อกำหนดในการติดตั้ง:

# Use an official Python runtime as a parent image
FROM python:3.6-alpine

# install some packages necessary to scrapy and then curl because it's  handy for debugging
RUN apk --update add linux-headers libffi-dev openssl-dev build-base libxslt-dev libxml2-dev curl python-dev

WORKDIR /my_scraper

ADD requirements.txt /my_scraper/

RUN pip install -r requirements.txt

ADD . /scrapers

และในที่สุดก็นำมารวมกันเป็นระบบ docker-compose.yaml :

version: '2'
services:
  selenium:
    image: selenium/standalone-chrome
    ports:
      - "4444:4444"
    shm_size: 1G

  my_scraper:
    build: .
    depends_on:
      - "selenium"
    environment:
      - SELENIUM_LOCATION=samplecrawler_selenium_1
    volumes:
      - .:/my_scraper
    # use this command to keep the container running
    command: tail -f /dev/null

docker-compose up -dวิ่ง หากคุณทำเช่นนี้เป็นครั้งแรกมันจะใช้เวลาสักครู่เพื่อดึงซีลีเนียม / สแตนด์อโลน - โครเมียมล่าสุดและสร้างภาพมีดโกนของคุณเช่นกัน

เมื่อเสร็จแล้วคุณสามารถตรวจสอบว่าคอนเทนเนอร์ของคุณทำงานด้วยหรือไม่ docker psและตรวจสอบว่าชื่อของซีลีเนียมคอนเทนเนอร์ตรงกับของตัวแปรสภาพแวดล้อมที่เราส่งผ่านไปยังคอนเทนเนอร์มีดโกนของเรา (ที่นี่มันคือSELENIUM_LOCATION=samplecrawler_selenium_1)

ป้อนที่เก็บมีดโกนของคุณด้วยdocker exec -ti YOUR_CONTAINER_NAME sh, คำสั่งสำหรับฉันคือdocker exec -ti samplecrawler_my_scraper_1 sh, cd ในไดเรกทอรีที่ถูกต้องและเรียกใช้มีดโกนของคุณด้วยscrapy crawl my_spiderลงในไดเรกทอรีที่เหมาะสมและใช้มีดโกนของคุณด้วย

สิ่งทั้งหมดอยู่ในหน้า GitHub ของฉันและคุณสามารถรับได้จากที่นี่


5

การผสมผสานของ BeautifulSoup และ Selenium เข้ากันได้ดีมากสำหรับฉัน

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from bs4 import BeautifulSoup as bs

driver = webdriver.Firefox()
driver.get("http://somedomain/url_that_delays_loading")
    try:
        element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "myDynamicElement"))) #waits 10 seconds until element is located. Can have other wait conditions  such as visibility_of_element_located or text_to_be_present_in_element

        html = driver.page_source
        soup = bs(html, "lxml")
        dynamic_text = soup.find_all("p", {"class":"class_name"}) #or other attributes, optional
    else:
        print("Couldnt locate element")

ป.ล. คุณสามารถค้นหาเงื่อนไขการรอเพิ่มเติมได้ที่นี่


4

คุณจะต้องการใช้ urllib, คำขอ, ไดรเวอร์เว็บสวยงามและซีลีเนียมในสคริปต์ของคุณสำหรับส่วนต่าง ๆ ของหน้า, (เพื่อชื่อไม่กี่)
บางครั้งคุณจะได้สิ่งที่คุณต้องการด้วยเพียงแค่หนึ่งในโมดูลเหล่านี้
บางครั้งคุณจะต้องใช้โมดูลสองสามหรือทั้งหมด
บางครั้งคุณต้องปิด js ในเบราว์เซอร์ของคุณ
บางครั้งคุณอาจต้องการข้อมูลส่วนหัวในสคริปต์ของคุณ
ไม่มีเว็บไซต์ใดสามารถถูกคัดลอกมาในลักษณะเดียวกันและไม่มีเว็บไซต์ใดสามารถถูกคัดลอกในลักษณะเดียวกันตลอดไปโดยไม่ต้องแก้ไขโปรแกรมรวบรวมข้อมูลของคุณโดยปกติหลังจากผ่านไปสองสามเดือน แต่พวกเขาทั้งหมดสามารถถูกคัดลอก! จะมีวิธีที่แน่นอน
หากคุณต้องการข้อมูลที่ถูกคัดลอกอย่างต่อเนื่องในอนาคตเพียงแค่ขูดทุกสิ่งที่คุณต้องการและเก็บไว้ในไฟล์. dat พร้อมดอง
เพียงแค่ทำการค้นหาวิธีการลองกับโมดูลเหล่านี้และคัดลอกและวางข้อผิดพลาดของคุณลงใน Google


3

ใช้ PyQt5

from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QUrl
from PyQt5.QtWebEngineWidgets import QWebEnginePage
import sys
import bs4 as bs
import urllib.request


class Client(QWebEnginePage):
    def __init__(self,url):
        global app
        self.app = QApplication(sys.argv)
        QWebEnginePage.__init__(self)
        self.html = ""
        self.loadFinished.connect(self.on_load_finished)
        self.load(QUrl(url))
        self.app.exec_()

    def on_load_finished(self):
        self.html = self.toHtml(self.Callable)
        print("Load Finished")

    def Callable(self,data):
        self.html = data
        self.app.quit()

# url = ""
# client_response = Client(url)
# print(client_response.html)

1

ฉันพยายามค้นหาคำตอบสำหรับคำถามนี้เป็นเวลาสองวัน คำตอบมากมายนำคุณไปสู่ปัญหาที่แตกต่างกัน แต่คำตอบของพญานาคด้านบนนั้นตรงประเด็นจริงๆ มันเป็นทางออกที่สั้นที่สุดและง่ายที่สุด เพียงเตือนความทรงจำคำสุดท้าย"var"แสดงถึงชื่อตัวแปรดังนั้นควรใช้เป็น:

 result = driver.execute_script('var text = document.title ; return text')

นี่ควรเป็นความเห็นต่อคำตอบของงูไม่ใช่คำตอบที่แยกจากกัน
Yserbius

1
เห็นได้ชัดว่า แต่ฉันยังไม่ได้ 50 reps เพื่อแสดงความคิดเห็นในคำตอบของคนอื่น
Abd_bgc

0

ฉันต้องจัดการกับปัญหาเดียวกันนี้ในบางโครงการที่ขูดเว็บด้วยตัวเอง วิธีที่ฉันจัดการกับมันคือการใช้ห้องสมุดร้องขอหลามเพื่อสร้างการร้องขอ HTTP โดยตรงไปยัง API แทนที่จะต้องโหลด JS

ไพ ธ อนร้องขอไลบรารีทำงานได้ดีสำหรับสิ่งนี้และคุณสามารถเห็นคำขอ http โดยใช้องค์ประกอบการตรวจสอบและนำทางไปยังแท็บเครือข่าย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.