如何使用Python Beautiful Soup从下拉菜单中提取数据

4
我正在尝试从一个网站上爬取数据,该网站具有多级下拉菜单,每次选择一个项目时,它都会更改子下拉菜单的子项。 问题是,在每个循环中它提取相同的下拉列表项。虽然进行了选择,但它没有根据循环中的新选择更新项目。 有人能帮我解决为什么我没有得到想要的结果吗? 也许这是因为我的下拉列表在Java Script或其他什么东西中。
例如,像下面图片中的菜单: image of the dropdown 我已经走到了这一步:
enter code here

from selenium import webdriver
from selenium.webdriver.support.ui import Select
from selenium.webdriver.common.by import By
import csv

//#from selenium.webdriver.support import Select 
import time

print ("opening chorome....")  
driver = webdriver.Chrome()
driver.get('https://www.wheelmax.com/')
time.sleep(10)

csvData = ['Year', 'Make', 'Model', 'Body', 'Submodel', 'Size']

//#variables
yeart = []
make= []
model=[]
body = []
submodel = []
size = []
Yindex = Mkindex = Mdindex = Bdindex = Smindex = Sindex = 0

print ("waiting for program to set variables....")
time.sleep(20)

print ("initializing and setting variables....")

//#initializing Year
Year = Select(driver.find_element_by_id("icm-years-select"))
Year.select_by_value('2020')
yr = driver.find_elements(By.XPATH, '//*[@id="icm-years-select"]')
time.sleep(15)

//#initializing Make
Make = Select(driver.find_element_by_id("icm-makes-select"))
Make.select_by_index(1)
mk = driver.find_elements(By.XPATH, '//*[@id="icm-makes-select"]')
time.sleep(15)

//#initializing Model
Model = Select(driver.find_element_by_id("icm-models-select"))
Model.select_by_index(1)
mdl = driver.find_elements(By.XPATH, '//*[@id="icm-models-select"]')
time.sleep(15)

//#initializing body
Body = Select(driver.find_element_by_id("icm-drivebodies-select"))
Body.select_by_index(1)
bdy = driver.find_elements(By.XPATH, '//*[@id="icm-drivebodies-select"]')
time.sleep(15)

//#initializing submodel
Submodel = Select(driver.find_element_by_id("icm-submodels-select"))
Submodel.select_by_index(1)
sbm = driver.find_elements(By.XPATH, '//*[@id="icm-submodels-select"]')
time.sleep(15)

//#initializing size
Size = Select(driver.find_element_by_id("icm-sizes-select"))
Size.select_by_index(0)
siz = driver.find_elements(By.XPATH, '//*[@id="icm-sizes-select"]')
time.sleep(5)


Cyr = Cmk = Cmd = Cbd = Csmd = Csz = ""

print ("fetching data from variables....")

for y in yr:
    obj1 = driver.find_element_by_id("icm-years-select")
    Year = Select(obj1)
    Year.select_by_index(++Yindex)
    obj1.click()
    #obj1.click()
    yeart.append(y.text)
    Cyr = y.text
    time.sleep(10)
    for m in mk:
        obj2 = driver.find_element_by_id("icm-makes-select")
        Make = Select(obj2)
        Make.select_by_index(++Mkindex)
        obj2.click()
        #obj2.click()
        make.append(m.text)
        Cmk = m.text
        time.sleep(10)
        for md in mdl:
            Mdindex =0
            obj3 = driver.find_element_by_id("icm-models-select")
            Model = Select(obj3)
            Model.select_by_index(++Mdindex)
            obj3.click()
            #obj3.click(clickobj)
            model.append(md.text)
            Cmd = md.text
            time.sleep(10)
            Bdindex = 0
            for bd in bdy:
                obj4 = driver.find_element_by_id("icm-drivebodies-select")
                Body = Select(obj4)
                Body.select_by_index(++Bdindex)
                obj4.click()
                #obj4.click(clickobj2)
                body.append(bd.text)
                Cbd = bd.text
                time.sleep(10)
                Smindex = 0
                for sm in sbm:
                    obj5 = driver.find_element_by_id("icm-submodels-select")
                    Submodel = Select(obj5)
                    obj5.click()
                    Submodel.select_by_index(++Smindex)
                    #obj5.click(clickobj5)
                    submodel.append(sm.text)
                    Csmd = sm.text
                    time.sleep(10)
                    Sindex = 0
                    for sz in siz:
                        Size = Select(driver.find_element_by_id("icm-sizes-select"))
                        Size.select_by_index(++Sindex)
                        size.append(sz.text)
                        Scz = sz.text
                        csvData += [Cyr, Cmk, Cmd, Cbd,Csmd, Csz]
3个回答

1
因为 https://www.wheelmax.com 有多级下拉菜单,相互依赖,例如如果您选择 Select Year 下拉选项,则在选择了年份后,基于所选年份的 Select Make 下拉将启用并显示选项。
所以,基本上您需要使用 Selenium 包来处理动态选项。
根据您的浏览器安装 Selenium web driver。 下载 Chrome web driver:

http://chromedriver.chromium.org/downloads

Install web driver for chrome browser:

unzip ~/Downloads/chromedriver_linux64.zip -d ~/Downloads
chmod +x ~/Downloads/chromedriver
sudo mv -f ~/Downloads/chromedriver /usr/local/share/chromedriver
sudo ln -s /usr/local/share/chromedriver /usr/local/bin/chromedriver
sudo ln -s /usr/local/share/chromedriver /usr/bin/chromedriver

selenium教程

https://selenium-python.readthedocs.io/

使用Selenium选择多个下拉选项的示例。
from selenium import webdriver
from selenium.webdriver.support.ui import Select
import time

driver = webdriver.Chrome()
driver.get('https://www.wheelmax.com/')
time.sleep(4)

selectYear = Select(driver.find_element_by_id("icm-years-select"))
selectYear.select_by_value('2019')

time.sleep(2)

selectMakes = Select(driver.find_element_by_id("icm-makes-select"))
selectMakes.select_by_value('58')

更新:

选择下拉选项值或计算总选项数。

for option in selectYear.options:
    print(option.text)

print(len(selectYear.options))

查看更多


你确定 Selenium 可以解决这个问题吗?我需要提取全部数据!! - Geek Online
@GeekOnline 是的,selenium可以解决你的问题,让我添加一些代码来指导你如何使用selenium。 - bharatk
我有一个问题!如何选择或计算特定下拉菜单中的所有项目,大多数答案都是关于Java的。 - Geek Online

1

如何使用Python Beautiful Soup从下拉菜单中提取数据

该页面通过回调来填充年份。只需模仿即可。

如果您确实需要更改年份并从依赖的下拉菜单中进行选择,这将成为另一个问题,您需要浏览器自动化,例如Selenium,或手动执行此操作并检查网络选项卡以查看是否有XHR请求可以模仿以提交您的选择。

import requests
​
r = requests.get('https://www.iconfigurators.com/json2/?returnType=json&bypass=true&id=13898&callback=yearObj').json()
years = [item['year'] for item in r['years']]
print(years)

你能否建议一下我如何实现有依赖关系的下拉菜单? - Geek Online
你的意思是根据选择检索数据,还是只是下拉菜单之间的映射关系? - QHarr
你想推荐我学习网页抓取的任何链接吗?我正在尝试自学。 - Geek Online
是的,我的意思是根据选择检索数据,我需要它用于我的网站。 - Geek Online
如果从非自己的网站获取内容,请小心。请参考我的回答中关于进行选择的中间部分。我建议查看现有的SO问题并发布一个新问题。关于链接 - 我知道有很多Python网络爬虫教程。我尝试了几个,但没有找到我真正喜欢的Python语言教程。您可以在StackOverflow和YouTube上找到大部分所需内容。 - QHarr
谢谢兄弟告诉我关于这件事的抄袭和版权问题,我真的不知道!我正在尝试获取同样问题的开源答案! - Geek Online

0
我猜测你无法使用beautiful soup解析年份的原因是,包含所有年份选项标签的'select'标签在beautiful soup下载页面时还未出现/被隐藏。我认为它是通过执行额外的JavaScript添加到DOM中的。如果你使用浏览器的开发者工具(例如Mozilla的F12)查看加载页面的DOM,你会发现包含你要查找信息的标签是:<select id="icm-years-select"">。如果你尝试使用beautiful soup下载的对象解析此标签,你将得到一个空的标签对象列表:
from bs4 import BeautifulSoup
from requests import get
response = get('https://www.wheelmax.com/')
yourSoup = BeautifulSoup(response.text, "lxml")
print(len(yourSoup.select('div #vehicle-search'))) // length = 1 -> visible
print()
print(len(yourSoup.select('#icm-years-select')))    // length = 0 -> not visible

如果你想用Python获取年份,那么你可以尝试点击相关标签,然后再使用一些组合的requests/beautiful soup/或selenium模块进行解析,这需要更多的挖掘 :-)

否则,如果你只是需要快速解析年份,可以使用JavaScript:

countYears = document.getElementById('icm-years-select').length;
yearArray = [];
for (i = 0; i < countYears; i++) {yearArray.push(document.getElementById('icm-years-select')[i].value)};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接