【问题标题】:Trouble with webscraping, how to NA when no results?网页抓取有问题,没有结果时如何NA?
【发布时间】:2020-11-20 19:24:57
【问题描述】:

我有几个链接到酒店页面的 URL,我想从中抓取一些数据。

我正在使用以下这个脚本,但我想更新它:

data=[]

for i in range(0,10):
    url = final_list[i]
    driver2 = webdriver.Chrome()
    driver2.get(url)  
    sleep(randint(10,20))
    soup = BeautifulSoup(driver2.page_source, 'html.parser')

    my_table2 = soup.find_all(class_=['title-2', 'rating-score body-3'])
    
    review=soup.find_all(class_='reviews')[-1]
    
    try:
        price=soup.find_all('span', attrs={'class':'price'})[-1] 
    except:
        price=soup.find_all('span', attrs={'class':'price'})

    for tag in my_table2:
        data.append(tag.text.strip())
        
    for p in price:
        data.append(p)
        
    for r in review:
        data.append(r)   

但问题出在这里,tag.text.strip() 像这里一样刮掉评分数字:

它会将数字评分剥离为单独的值,但某些酒店的评分数量不同。这是一个有 7 个评分的酒店,默认数字是 8。有些有 7 个评分,其他 6 个,依此类推。所以最后,我的数据框很糟糕。如果酒店没有 8 个评分,则该值将被转移。

我的问题是:如何告诉脚本“如果这个 tag.text.strip(i) 中有一个值,那么就放这个值,但如果没有放 None。当然,它是八个值.

我尝试了几件事,例如:

for tag in my_table2:
    for i in tag.text.strip()[i]:
        if i:
            data.append(i)
        else:
            data.append(None)

但不幸的是,这无济于事,所以如果你能帮助找出答案,那就太棒了:)

如果这可以帮助你,我把链接放在我正在抓取的酒店上:

https://www.hostelworld.com/pwa/hosteldetails.php/Itaca-Hostel/Barcelona/1279?from=2020-11-21&to=2020-11-22&guests=1

数字评分在最后

谢谢。

【问题讨论】:

  • 你能添加一些示例 HTML 代码吗?例如一个有 6 个评分,一个有 8 个评分?
  • 为您的data 使用字典怎么样?例如data['price'] = p data['review'] = r?
  • 什么意思?是的,给我 2 分钟,我会检查 html 并更新我的帖子
  • 把所有的html都放太长,所以我把链接放在一些酒店上。
  • 你能添加一个有 6 或 8 个评分的链接吗?

标签: python python-3.x selenium web-scraping beautifulsoup


【解决方案1】:

一些建议:

  • 将您的数据放入字典中。您不必假设所有标签都存在并且标签的顺序无关紧要。您可以使用

    获取标签和相应的评级
    rating_labels = soup.find_all(class_=['rating-label body-3'])
    rating_scores = soup.find_all(class_=['rating-score body-3'])
    

    然后用zip遍历这两个列表

  • driver 移出循环,打开一次就足够了

  • 不要使用wait,而是使用 Selenium 的等待函数。您可以等待特定元素出现或填充WebDriverWait(driver, 10).until(EC.presence_of_element_located(your_element)

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

  • 将您抓取的 HTML 代码缓存到文件中。它对你来说更快,对你正在抓取的网站更有礼貌


import selenium
import selenium.webdriver
import time
import random
import os
from bs4 import BeautifulSoup

data = []

final_list = [
    'https://www.hostelworld.com/pwa/hosteldetails.php/Itaca-Hostel/Barcelona/1279?from=2020-11-21&to=2020-11-22&guests=1',
    'https://www.hostelworld.com/pwa/hosteldetails.php/Be-Ramblas-Hostel/Barcelona/435?from=2020-11-27&to=2020-11-28&guests=1'
]

# load your driver only once to save time
driver = selenium.webdriver.Chrome()

for url in final_list:
    data.append({})

    # cache the HTML code to the filesystem
    # generate a filename from the URL where all non-alphanumeric characters (e.g. :/) are replaced with underscores _
    filename = ''.join([s if s.isalnum() else '_' for s in url])
    if not os.path.isfile(filename):
        driver.get(url)
        
        # better use selenium's wait functions here  
        time.sleep(random.randint(10, 20))
        source = driver.page_source
        with open(filename, 'w', encoding='utf-8') as f:
            f.write(source)
    else:
        with open(filename, 'r', encoding='utf-8') as f:
            source = f.read()
    soup = BeautifulSoup(source, 'html.parser')

    review = soup.find_all(class_='reviews')[-1]
    
    try:
        price = soup.find_all('span', attrs={'class':'price'})[-1] 
    except:
        price = soup.find_all('span', attrs={'class':'price'})

    data[-1]['name'] = soup.find_all(class_=['title-2'])[0].text.strip()
    
    rating_labels = soup.find_all(class_=['rating-label body-3'])
    rating_scores = soup.find_all(class_=['rating-score body-3'])
    assert len(rating_labels) == len(rating_scores)
    for label, score in zip(rating_labels, rating_scores):
        data[-1][label.text.strip()] = score.text.strip()
    
    data[-1]['price'] = price.text.strip()
    data[-1]['review'] = review.text.strip()
  • 然后可以使用 Pandas 轻松地将数据放入格式良好的表格中

    import pandas as pd
    df = pd.DataFrame(data)
    df
    

  • 如果某些数据丢失/不完整,Pandas 会将其替换为 'NaN'

    data.append(data[0].copy())
    del(data[-1]['Staff'])
    data[-1]['name'] = 'Incomplete Hostel'
    pd.DataFrame(data)
    

【讨论】:

  • 感谢您的精彩回答 :) 我会尽快查看!
  • 你好 :) 为什么使用 isalnum ?我想知道。其实我不明白'try'之前的第一部分
  • @LaurieFalcon:它将 URL 转换为可以存储在大多数文件系统上的字符串。 isalnum() 为字母数字字符返回 True,即所有特殊字符都转换为下划线。
  • @MaximilianPeters 是否可以在适用于您提出的解决方案的地方添加相关的 cmets?我认为这样代码会更具可读性。例如,对isalnumcache html codedata[-1]['price'] 等说一行注释。为什么 selenium wait() 而不是 python 核心类 wait 等的原因。
  • @MaximilianPeters 代表社区,我有责任祝贺您的迅速行动,以提高代码的可读性。加上1'ed的答案。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-23
  • 1970-01-01
  • 2020-07-03
  • 1970-01-01
相关资源
最近更新 更多