【问题标题】:Webscraping using python for a webpage having "Mehr Anseigen" i.e(eng: Show more)使用 python 对具有“Mehr Anzeigen”的网页进行网络抓取,即(eng:显示更多)
【发布时间】:2022-11-12 08:04:39
【问题描述】:

我一直在尝试抓取网页并将一些详细信息放入 excel 或 CSV 中。但由于页面有Mehr Anzeigen,在德语中是“显示更多”,因此无法获取所有内容。

网址:https://www.gelbeseiten.de/suche/architekturb%c3%bcros/aachen?umkreis=21000

From the above ``URL`` I would like to extract:

<h2> class='Title',

<address> class= 'mod-AdresseKompakt'

<adress> class= 'nbr'

. .

and so on.

几乎我想自动加载所有内容(点击“显示更多”30次很困难) 并从完全加载的网站中提取所有详细信息。

我已经阅读了 Stack-Overflow 和一些博客中的一些可用线程,但对于不同的网站,每个线程都是不同的。

任何帮助都会很棒!

Python: 我对 Python 有一定了解,但对 HTML 和 JS 很陌生。

from selenium import webdriver 
from selenium.webdriver.common.by import By 
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys 
from selenium.webdriver.support import expected_conditions as EC 
from selenium.common.exceptions import TimeoutException


path_to_chromedriver = '/Users/kuk/Desktop/chromedriver' # change path as needed
browser = webdriver.Chrome(executable_path = path_to_chromedriver)

url = 'https://www.gelbeseiten.de/suche/architekturb%c3%bcros/aachen?umkreis=21000'
browser.get(url)


h2 = browser.find_elements(By.TAG_NAME, 'h2')
for item in h2:  
print(item.text)

【问题讨论】:

  • 您想从“Mehr Anzeigen”页面获得什么?标题,地址和号码[以及电子邮件和网站]可以从url本身获得......
  • 是的,我还需要电子邮件、电话号码和网站 抱歉,您能解释一下如何获取页面中所有 324 个条目的信息吗?我不明白您的意思是“可以从url 获得”任何示例代码都会有所帮助。
  • 抱歉,我将它与“Mehr Details”按钮混为一谈...我已经发布了一个使用 BeautifulSoup 的潜在解决方案,因为我已经有一个 selenium+bs4 scraper 功能以及一个与答案中的非常相似的功能通过 css 选择器从 bs4 标签中获取详细信息,这对我来说更简单;但如果你想要/需要,我也可以添加一个只使用硒的解决方案
  • 这真是令人印象深刻的解决方案,感谢您投入时间和精力。您能否也仅与 Selenium 分享解决方案,它在其他情况下会很有用。
  • @Kuladeep-我在我的答案中添加了一个编辑

标签: python html web-scraping


【解决方案1】:

我有a function (linkToSoup_selenium),它可以点击按钮一定次数,然后抓取页面

# import pandas # for saving as table
# from linkToSoup_selenium import * ## OR PASTE HERE

cfList = (
    ['//div[@id="cmpbox"]//span[@id="cmpbntyestxt"]'] # "Akzeptieren" - for cookies, I think
    + ['//a[@id="mod-LoadMore--button"]']*30 # click LoadMore 30x
)

soup = linkToSoup_selenium(
     'https://www.gelbeseiten.de/suche/architekturb%c3%bcros/aachen?umkreis=21000'
    , ecx='//article[327]' # wait for listing #327 to load
    , clickFirst=cfList  # cookies + 30xLoadMore
    , strictMode=False # (is False by default but) do NOT set as True 
)

(您可以将其保存为文件并导入或粘贴到代码的开头。)通过clickFirst 参数[要单击的元素的xpaths 列表],将“Mehr Anzeigen”的XPath 添加为多次单击(最好高估,因为它只会在无法单击时打印错误消息,但由于它位于隔离的 try 块内,程序的其余部分将继续 - 这就是 @987654330 的原因@ 在这里很重要)。


然后,要获取详细信息,您可以定义如下函数

def getListingDetails(lSoup, refDict):
    detList = {}
    for k, sel in refDict.items():
        s = lSoup.select_one(sel)
        if s is None:
            detVal = None
        elif '[href' in sel:
            detVal = s.get('href')
            if '"mailto:"' in sel:
                detVal = detVal.replace("mailto:", '', 1)
                detVal = detVal.split('?')[0]
        else:
            detVal = s.get_text(' ', strip=True)

        detList[k] = detVal
    return detList

以及每个细节的selectors字典

selRef = {
    'Title': 'h2[data-wipe-name="Titel"]',
    'Branch': 'p.mod-Treffer--besteBranche',
    'Address': 'p[data-wipe-name="Adresse"]',
    'Contact': 'p[data-wipe-name="Kontaktdaten"]',
    'Website': 'a.contains-icon-homepage[href]',
    'Email': 'a.contains-icon-email[href^="mailto:"]',
    'DetailsPage': 'a.contains-icon-details[href]'
}

然后,您可以简单地将列表推导与getListingDetails [从上面] 和select 一起使用,然后使用pandas 保存

if soup:
    lDets = [
        getListingDetails(a, selRef)
        for a in soup.select('article[id^="treffer_"]')
    ]

    pandas.DataFrame(lDets).to_csv('listingDetails.csv', index=False) # save

lDets 是与selRef 格式相同的字典列表,但包含广告的详细信息而不是选择器。)

生成的 CSV 看起来像



[编辑] 没有 BeautifulSoup 的硒

首先,清除cookies弹出然后重复加载更多没有该功能,

ac_xpath = '//div[@id="cmpbox"]//span[@id="cmpbntyestxt"]'
WebDriverWait(browser, 25).until(EC.visibility_of_all_elements_located((By.XPATH, ac_xpath)))
browser.find_element(By.XPATH, ac_xpath).click()

loadMore_xpath = '//a[@id="mod-LoadMore--button"]'
loadMore_maxClicks = 50
for lm_clickCt in range(loadMore_maxClicks):
    print('', end=f'
Clicked "Mehr Anzeigen" {lm_clickCt} times')

    WebDriverWait(browser, 25).until(EC.visibility_of_all_elements_located((By.XPATH, loadMore_xpath)))
    loadMore_btn = browser.find_elements(By.XPATH, loadMore_xpath)
    browser.execute_script("arguments[0].scrollIntoView(false);", loadMore_btn[0])

    if not loadMore_btn: break
    loadMore_btn[0].click()
print('')

一旦按钮消失或单击最大次数(50 次)后,它将停止尝试加载更多;如果您不想设置最大值,请使用while True 而不是for lm_clickCt in range(loadMore_maxClicks),但有时该按钮对我不起作用(即使我直接使用浏览器)并且我不希望程序挂起由于无限循环。

对于提取细节,selRef 可以保持原样,但需要调整 getListingDetails 以处理 Selenium 元素而不是 bs4 标签 - 而不是 selectget,我们将不得不使用 [分别] find_elementsget_attribute

def getListingDetails(listingEl, refDict):
    detList = {}
    for k, sel in refDict.items():
        s = listingEl.find_elements(By.CSS_SELECTOR, sel)
        if not s:
            detVal = None
        elif '[href' in sel:
            detVal = s[0].get_attribute('href')
            if '"mailto:"' in sel:
                detVal = detVal.replace("mailto:", '', 1)
                detVal = detVal.split('?')[0]
        else:
            detVal = s[0].get_attribute('innerText').strip()

        detList[k] = detVal
    return detList

并且创建lDets 看起来也与之前非常相似

lDets = [
    getListingDetails(a, selRef) for a in
    browser.find_elements(By.CSS_SELECTOR, 'article[id^="treffer_"]')
]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-25
    • 2021-07-26
    • 1970-01-01
    • 2011-10-21
    • 1970-01-01
    • 2017-09-26
    相关资源
    最近更新 更多