【问题标题】:Trying to scrape a specific part of html with Python-3.7, but it returns "None"尝试使用 Python-3.7 抓取 html 的特定部分,但它返回“无”
【发布时间】:2019-04-11 15:42:23
【问题描述】:

我是一个初学者,正在编写一些简单的 Python 代码来从网页中抓取数据。我已经找到了要抓取的 html 的确切部分,但它一直返回“无”。它适用于网页的其他部分,但不适用于这一特定部分

我正在使用 BeautifulSoup 来解析 html,因为我可以抓取一些代码,所以我假设我不需要使用 Selenium。但我仍然找不到如何抓取特定部分。

这是我编写的 Python 代码:

import requests

from bs4 import BeautifulSoup


url = 'https://www.rent.com/new-york/tuckahoe-apartments?page=2'

response = requests.get(url)

html_soup = BeautifulSoup(response.text, 'html.parser')

apt_listings = html_soup.find_all('div', class_='_3RRl_')
print(type(apt_listings))
print(len(apt_listings))

first_apt = apt_listings[0]

first_apt.a

first_add = first_apt.a.text

print(first_add)


apt_rents = html_soup.find_all('div', class_='_3e12V')
print(type(apt_rents))
print(len(apt_rents))

first_rent = apt_rents[0]

print(first_rent)

first_rent = first_rent.find('class', attrs={'data-tid' : 'price'})

print(first_rent)

这是 CMD 的输出:

<class 'bs4.element.ResultSet'>
30
address not disclosed
<class 'bs4.element.ResultSet'>
30
<div class="_3e12V" data-tid="price">$2,350</div>
None

“地址未公开”是正确的,已成功抓取。 我想刮掉 2,350 美元,但它一直返回“无”。 我想我已经接近正确,但我似乎无法获得 2,350 美元。非常感谢任何帮助。

【问题讨论】:

    标签: html web-scraping python-3.7


    【解决方案1】:

    你需要像这样使用 BeautifulSoup 的 .text 属性而不是 .find() :

    first_rent = first_rent.text
    

    就这么简单。

    【讨论】:

    • 谢谢 JacopoDT。我尝试了你的建议,它返回了一个错误:&lt;class 'bs4.element.ResultSet'&gt; 30 address not disclosed &lt;class 'bs4.element.ResultSet'&gt; 30 &lt;div class="_3e12V" data-tid="price"&gt;$2,350&lt;/div&gt; Traceback (most recent call last): File "bvilleaptsprelim.py", line 39, in &lt;module&gt; first_rent = first_rent.text AttributeError: 'NoneType' object has no attribute 'text'
    • 我表达得很糟糕,你应该在 .find() 之后使用 .text 而不是它。
    • 再次感谢,但还是不行:&lt;class 'bs4.element.ResultSet'&gt; 30 address not disclosed &lt;class 'bs4.element.ResultSet'&gt; 30 &lt;div class="_3e12V" data-tid="price"&gt;$2,350&lt;/div&gt; Traceback (most recent call last): File "bvilleaptsprelim.py", line 37, in &lt;module&gt; first_rent = first_rent.text('class', attrs={'data-tid' : 'price'}) TypeError: 'str' object is not callable
    • 不,.text 是一种属性,而不是一种方法,请将 first_rent = first_rent.find('class', attrs={'data-tid' : 'price'}) 更改为 first_rent = first_rent.text
    【解决方案2】:

    您可以从脚本标签中提取所有列表并解析为 json。正则表达式查找以window.__APPLICATION_CONTEXT__ = 开头的脚本标记。

    之后的字符串是通过正则表达式(.*) 中的组提取的。如果使用 json.loads 加载字符串,则该 javascript 对象可以解析为 json。

    你可以探索json对象here

    import requests
    import json
    from bs4 import BeautifulSoup as bs
    import re
    base_url = 'https://www.rent.com/'
    res = requests.get('https://www.rent.com/new-york/tuckahoe-apartments?page=2')
    soup = bs(res.content, 'lxml')
    r = re.compile(r'window.__APPLICATION_CONTEXT__ = (.*)')
    data = soup.find('script', text=r).text
    script = r.findall(data)[0]
    items = json.loads(script)['store']['listings']['listings']
    results = []
    
    for item in items:   
        address = item['address']
        area = ', '.join([item['city'], item['state'], item['zipCode']])
        low_price = item['aggregates']['prices']['low']
        high_price = item['aggregates']['prices']['high']
        listingId = item['listingId']
        url = base_url + item['listingSeoPath']
        # all_info = item
        record = {'address' : address,
                  'area' : area,
                  'low_price' : low_price,
                  'high_price' : high_price,
                  'listingId' : listingId,
                  'url' : url}
        results.append(record)
    df = pd.DataFrame(results, columns = [ 'address', 'area', 'low_price', 'high_price', 'listingId', 'url'])
    print(df)
    

    结果示例:


    带类的短版:

    import requests
    from bs4 import BeautifulSoup
    url = 'https://www.rent.com/new-york/tuckahoe-apartments?page=2'
    response = requests.get(url)
    
    soup = BeautifulSoup(response.text, 'html.parser')
    print(soup.select_one('._3e12V').text)
    

    所有价格:

    import requests
    from bs4 import BeautifulSoup
    url = 'https://www.rent.com/new-york/tuckahoe-apartments?page=2'
    response = requests.get(url)
    
    html_soup = BeautifulSoup(response.text, 'html.parser')
    print([item.text for item in html_soup.select('._3e12V')])
    

    【讨论】:

    • QHarr,难以置信,非常感谢。虽然这最终是我想要做的,但我不理解代码,正如我所提到的,我是一个初学者。我正在努力通过学习如何分别抓取每个文件以更好地了解代码的工作原理。我很欣赏你优雅的解决方案,但是,你有没有机会告诉我一个简单的修复方法来刮掉那一点?再次感谢您!
    • html_soup.select_one('._3e12V').text
    • 这也有效……而且……我明白了!谢谢QHarr!
    猜你喜欢
    • 1970-01-01
    • 2020-03-13
    • 1970-01-01
    • 1970-01-01
    • 2021-09-21
    • 1970-01-01
    • 2015-06-08
    • 2013-07-07
    • 1970-01-01
    相关资源
    最近更新 更多