用 Beautiful soup 抓取动态内容
Webscraping of dynamic content with Beautiful soup
为了训练我的 python 技能,我试图从“Arbeitsagentur”(https://www.arbeitsagentur.de/jobsuche/) 的网站上删除特定给定工作的空缺职位数量。我使用 firefox 浏览器的 web-developer 检查工具从包含信息的项目中提取文本,例如“12.231 个职位供 Informatiker/in”。我的代码:
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.support.ui import WebDriverWait
content = "https://www.arbeitsagentur.de/jobsuche/suche?angebotsart=1&was=Informatiker%2Fin"
options = Options()
options.add_argument('--headless')
driver = webdriver.Firefox(executable_path="C:/Drivers/geckodriver/geckodriver.exe", options=options)
driver.get(content)
soup = BeautifulSoup(driver.page_source, 'html.parser')
num_jobs = soup.select_one('div[class="h1-zeile-suche-speichern-container-content container-fluid"] h2')
print(num_jobs)
driver.close()
结果我提取了正确的行,但它不包括查询的信息。翻译成英文我得到这个输出:
<h2 _ngcontent-serverapp-c39="" class="h6" id="suchergebnis-h1-anzeige">Jobs for Informatiker/in are loaded</h2>
在 firefox 的网络检查器中,我看到的是:
<h2 id="suchergebnis-h1-anzeige" class="h6" _ngcontent-serverapp-c39="">
12.231 Jobs für Informatiker/in</h2>
我尝试了 WebDriverWait 方法和 driver.implicitly_wait() 来等待网页完全加载但没有成功。
可能这个值是由 js 脚本(?)计算和插入的。因为我不是 Web 开发人员,所以我不知道它是如何工作的,也不知道如何正确提取具有给定作业数量的行。我尝试使用 firefox 开发人员工具的调试器来查看值的计算位置/方式。但大多数脚本只是非常隐晦的一行代码。
(通过正则表达式从字符串/文本行中提取 number/value 完全没有问题)。
非常感谢您的支持或任何有用的提示。
由于内容是动态加载的,所以number of job result
只有在某个元素可见后才能解析,那样的话,所有元素都会被加载,你就可以成功解析你想要的数据了。
您也可以增加睡眠时间以加载所有数据,但这是一个糟糕的解决方案。
工作代码-
import time
from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from webdriver_manager.chrome import ChromeDriverManager
options = webdriver.ChromeOptions()
# options.add_argument("--headless")
options.add_argument("--no-sandbox")
options.add_argument("--disable-gpu")
options.add_argument("--window-size=1920x1080")
options.add_argument("--disable-extensions")
chrome_driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()),
options=options
)
def arbeitsagentur_scraper():
URL = "https://www.arbeitsagentur.de/jobsuche/suche?angebotsart=1&was=Informatiker%2Fin"
with chrome_driver as driver:
driver.implicitly_wait(15)
driver.get(URL)
wait = WebDriverWait(driver, 10)
# time.sleep(10) # increase the load time to fetch all element, not advised solution
# wait until this element is visible
wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, '.liste-container')))
elem = driver.find_element(By.XPATH,
'/html/body/jb-root/main/jb-jobsuche/jb-jobsuche-suche/div[1]/div/jb-h1zeile/h2')
print(elem.text)
arbeitsagentur_scraper()
输出-
12.165 Jobs für Informatiker/in
或者,您可以使用他们的 API URL 加载结果。例如:
import json
import requests
api_url = "https://rest.arbeitsagentur.de/jobboerse/jobsuche-service/pc/v4/jobs"
query = {
"angebotsart": "1",
"was": "Informatiker/in",
"page": "1",
"size": "25",
"pav": "false",
}
headers = {
"OAuthAccessToken": "eyJhbGciOiJIUzUxMiJ9.eyAic3ViIjogIklkNFZSNmJoZFpKSjgwQ2VsbHk4MHI4YWpkMD0iLCAiaXNzIjogIk9BRyIsICJpYXQiOiAxNjU0MDM2ODQ1LCAiZXhwIjogMS42NTQwNDA0NDVFOSwgImF1ZCI6IFsgIk9BRyIgXSwgIm9hdXRoLnNjb3BlcyI6ICJhcG9rX21ldGFzdWdnZXN0LCBqb2Jib2Vyc2Vfc3VnZ2VzdC1zZXJ2aWNlLCBhYXMsIGpvYmJvZXJzZV9rYXRhbG9nZS1zZXJ2aWNlLCBqb2Jib2Vyc2Vfam9ic3VjaGUtc2VydmljZSwgaGVhZGVyZm9vdGVyX2hmLCBhcG9rX2hmLCBqb2Jib2Vyc2VfcHJvZmlsLXNlcnZpY2UiLCAib2F1dGguY2xpZW50X2lkIjogImRjZGVhY2JkLTJiNjItNDI2MS1hMWZhLWQ3MjAyYjU3OTg0OCIgfQ.BBkJbJ93fGqQQQGX4-VTzX8P6Twg8Rthq8meXV2WY_CoUmXQWhdgbjkFozP2BJXooSr7yLaTJr7JXEk8hDnCWA",
}
data = requests.get(api_url, params=query, headers=headers).json()
# uncomment to print all data:
# print(json.dumps(data, indent=4))
print(data["maxErgebnisse"])
打印:
12165
为了训练我的 python 技能,我试图从“Arbeitsagentur”(https://www.arbeitsagentur.de/jobsuche/) 的网站上删除特定给定工作的空缺职位数量。我使用 firefox 浏览器的 web-developer 检查工具从包含信息的项目中提取文本,例如“12.231 个职位供 Informatiker/in”。我的代码:
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.support.ui import WebDriverWait
content = "https://www.arbeitsagentur.de/jobsuche/suche?angebotsart=1&was=Informatiker%2Fin"
options = Options()
options.add_argument('--headless')
driver = webdriver.Firefox(executable_path="C:/Drivers/geckodriver/geckodriver.exe", options=options)
driver.get(content)
soup = BeautifulSoup(driver.page_source, 'html.parser')
num_jobs = soup.select_one('div[class="h1-zeile-suche-speichern-container-content container-fluid"] h2')
print(num_jobs)
driver.close()
结果我提取了正确的行,但它不包括查询的信息。翻译成英文我得到这个输出:
<h2 _ngcontent-serverapp-c39="" class="h6" id="suchergebnis-h1-anzeige">Jobs for Informatiker/in are loaded</h2>
在 firefox 的网络检查器中,我看到的是:
<h2 id="suchergebnis-h1-anzeige" class="h6" _ngcontent-serverapp-c39="">
12.231 Jobs für Informatiker/in</h2>
我尝试了 WebDriverWait 方法和 driver.implicitly_wait() 来等待网页完全加载但没有成功。 可能这个值是由 js 脚本(?)计算和插入的。因为我不是 Web 开发人员,所以我不知道它是如何工作的,也不知道如何正确提取具有给定作业数量的行。我尝试使用 firefox 开发人员工具的调试器来查看值的计算位置/方式。但大多数脚本只是非常隐晦的一行代码。
(通过正则表达式从字符串/文本行中提取 number/value 完全没有问题)。
非常感谢您的支持或任何有用的提示。
由于内容是动态加载的,所以number of job result
只有在某个元素可见后才能解析,那样的话,所有元素都会被加载,你就可以成功解析你想要的数据了。
您也可以增加睡眠时间以加载所有数据,但这是一个糟糕的解决方案。
工作代码-
import time
from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from webdriver_manager.chrome import ChromeDriverManager
options = webdriver.ChromeOptions()
# options.add_argument("--headless")
options.add_argument("--no-sandbox")
options.add_argument("--disable-gpu")
options.add_argument("--window-size=1920x1080")
options.add_argument("--disable-extensions")
chrome_driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()),
options=options
)
def arbeitsagentur_scraper():
URL = "https://www.arbeitsagentur.de/jobsuche/suche?angebotsart=1&was=Informatiker%2Fin"
with chrome_driver as driver:
driver.implicitly_wait(15)
driver.get(URL)
wait = WebDriverWait(driver, 10)
# time.sleep(10) # increase the load time to fetch all element, not advised solution
# wait until this element is visible
wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, '.liste-container')))
elem = driver.find_element(By.XPATH,
'/html/body/jb-root/main/jb-jobsuche/jb-jobsuche-suche/div[1]/div/jb-h1zeile/h2')
print(elem.text)
arbeitsagentur_scraper()
输出-
12.165 Jobs für Informatiker/in
或者,您可以使用他们的 API URL 加载结果。例如:
import json
import requests
api_url = "https://rest.arbeitsagentur.de/jobboerse/jobsuche-service/pc/v4/jobs"
query = {
"angebotsart": "1",
"was": "Informatiker/in",
"page": "1",
"size": "25",
"pav": "false",
}
headers = {
"OAuthAccessToken": "eyJhbGciOiJIUzUxMiJ9.eyAic3ViIjogIklkNFZSNmJoZFpKSjgwQ2VsbHk4MHI4YWpkMD0iLCAiaXNzIjogIk9BRyIsICJpYXQiOiAxNjU0MDM2ODQ1LCAiZXhwIjogMS42NTQwNDA0NDVFOSwgImF1ZCI6IFsgIk9BRyIgXSwgIm9hdXRoLnNjb3BlcyI6ICJhcG9rX21ldGFzdWdnZXN0LCBqb2Jib2Vyc2Vfc3VnZ2VzdC1zZXJ2aWNlLCBhYXMsIGpvYmJvZXJzZV9rYXRhbG9nZS1zZXJ2aWNlLCBqb2Jib2Vyc2Vfam9ic3VjaGUtc2VydmljZSwgaGVhZGVyZm9vdGVyX2hmLCBhcG9rX2hmLCBqb2Jib2Vyc2VfcHJvZmlsLXNlcnZpY2UiLCAib2F1dGguY2xpZW50X2lkIjogImRjZGVhY2JkLTJiNjItNDI2MS1hMWZhLWQ3MjAyYjU3OTg0OCIgfQ.BBkJbJ93fGqQQQGX4-VTzX8P6Twg8Rthq8meXV2WY_CoUmXQWhdgbjkFozP2BJXooSr7yLaTJr7JXEk8hDnCWA",
}
data = requests.get(api_url, params=query, headers=headers).json()
# uncomment to print all data:
# print(json.dumps(data, indent=4))
print(data["maxErgebnisse"])
打印:
12165