จะขูดเว็บไซต์จาวาสคริปต์ใน Python ได้อย่างไร

Sep 06 2020

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

URL: "https://www.todayonline.com/"

นี่เป็นสองวิธีที่ฉันได้ลอง แต่ล้มเหลว

วิธีที่ 1: ซุปสวย

tdy_url = "https://www.todayonline.com/"
page = requests.get(tdy_url).text
soup = BeautifulSoup(page)
soup  # Returns me a HTML with javascript text
soup.find_all('h3')

### Returns me empty list []

วิธีที่ 2: Selenium + BeautifulSoup

tdy_url = "https://www.todayonline.com/"

options = Options()
options.headless = True

driver = webdriver.Chrome("chromedriver",options=options)

driver.get(tdy_url)
time.sleep(10)
html = driver.page_source

soup = BeautifulSoup(html)
soup.find_all('h3')

### Returns me only less than 1/4 of the 'h3' tags found in the original page source 

กรุณาช่วย. ฉันได้ลองขูดเว็บไซต์ข่าวอื่น ๆ แล้วมันง่ายกว่ามาก ขอขอบคุณ.

คำตอบ

2 politicalscientist Sep 06 2020 at 15:38

คุณสามารถเข้าถึงข้อมูลผ่าน API (ดูแท็บเครือข่าย):


ตัวอย่างเช่น,

import requests
url = "https://www.todayonline.com/api/v3/news_feed/7"
data = requests.get(url).json()
2 Noname Sep 06 2020 at 15:39

มีหลายวิธีในการรวบรวมเนื้อหาของหน้าเว็บที่มี Javascript

  1. ใช้seleniumกับโปรแกรมควบคุมเว็บ Firefox
  2. ใช้เบราว์เซอร์ headless กับ phantomJS
  3. การเรียก API โดยใช้ไคลเอ็นต์ REST หรือrequestsไลบรารีpython

คุณต้องทำวิจัยของคุณก่อน

2 MananGajjar Sep 06 2020 at 16:04

ฉันจะแนะนำวิธีการที่ค่อนข้างง่าย

import requests
from bs4 import BeautifulSoup as bs

page = requests.get('https://www.todayonline.com/googlenews.xml').content
soup = bs(page)
news = [i.text for i in soup.find_all('news:title')]

print(news)

เอาท์พุท

['DBS named world’s best bank by New York-based financial publication',
 'Russia has very serious questions to answer on Navalny - UK',
 "Exclusive: 90% of China's Sinovac employees, families took coronavirus vaccine - CEO",
 'Three militants killed after fatal attack on policeman in Tunisia',
.....]

นอกจากนี้คุณสามารถตรวจสอบหน้า XML สำหรับข้อมูลเพิ่มเติมได้หากจำเป็น

ปล. ตรวจสอบความสอดคล้องก่อนทิ้งเว็บไซต์ทุกครั้ง :)

2 DemianWolf Sep 06 2020 at 16:00

ข้อมูลข่าวสารบนเว็บไซต์ที่คุณพยายามขูดนั้นดึงมาจากเซิร์ฟเวอร์โดยใช้ JavaScript (เรียกว่าXHR - XMLHttpRequest ) กำลังเกิดขึ้นแบบไดนามิกในขณะที่หน้าเว็บกำลังโหลดหรือกำลังเลื่อน ดังนั้นข้อมูลนี้จะไม่ถูกส่งกลับภายในเพจที่เซิร์ฟเวอร์ส่งคืน

ในตัวอย่างแรกคุณจะได้รับเฉพาะหน้าที่ส่งคืนโดยเซิร์ฟเวอร์ - โดยไม่มีข่าว แต่มี JS ที่ควรจะได้รับ ทั้งคำขอและ BeautifulSoup ไม่สามารถรัน JS ได้

อย่างไรก็ตามคุณสามารถลองสร้างคำขอที่ได้รับชื่อข่าวจากเซิร์ฟเวอร์ด้วยคำขอ Python ทำตามขั้นตอนต่อไปนี้:

  1. DevTools เปิดเบราว์เซอร์ของคุณ (โดยปกติคุณจะต้องกดF12หรือCtrl+ Shit+ Iสำหรับที่) และจะดูที่การร้องขอที่จะได้รับข่าวจากชื่อเซิร์ฟเวอร์ บางครั้งมันง่ายกว่าการขูดเว็บด้วย BeautifulSoup นี่คือภาพหน้าจอ (Firefox):
  1. คัดลอกลิงก์คำขอ (คลิกขวา -> คัดลอก -> คัดลอกลิงก์) requests.get(...)และผ่านมันไป

  2. ได้รับ.json()การร้องขอ มันจะส่งคืนคำสั่งที่ใช้งานง่าย เพื่อให้เข้าใจโครงสร้างของ dict ได้ดีขึ้นฉันขอแนะนำให้ใช้pprintแทนการพิมพ์แบบธรรมดา หมายเหตุคุณต้องทำfrom pprint import pprintก่อนใช้งาน

นี่คือตัวอย่างของรหัสที่ได้รับชื่อจากข่าวหลักในหน้า:

import requests


nodes = requests.get("https://www.todayonline.com/api/v3/news_feed/7")\
        .json()["nodes"]
for node in nodes:
    print(node["node"]["title"])

หากคุณต้องการรวบรวมกลุ่มข่าวภายใต้คำอธิบายภาพคุณต้องเปลี่ยนหมายเลขหลังจากnews_feed/ใน URL คำขอ (เพื่อให้ได้มาคุณเพียงแค่กรองคำขอโดยใช้ "news_feed" ใน DevTools และเลื่อนหน้าข่าวลง)

บางครั้งเว็บไซต์จะมีการป้องกันบอท (แม้ว่าเว็บไซต์ที่คุณพยายามขูดจะไม่มีก็ตาม) ในกรณีเช่นนี้คุณอาจต้องทำตามขั้นตอนเหล่านี้ด้วย