使用for循环进行网页抓取时出现None类型错误

时间:2020-08-23 05:57:58

标签: python beautifulsoup

在我的网页抓取技术中使用for循环时,似乎出现了错误。

这是我的app.py文件代码:

page_content = requests.get("http://books.toscrape.com/").content
parser = BookParser(page_content)

containers = parser.Content()
results = []

for container in containers:

    name = container.getName()
    link = container.getLink()
    price = container.getPrice()
    rating = container.getRating()

    results.append({'name': name,
                'link': link,
                'price': price,
                'rating': rating
                })  

print(results[4])

这是该函数的代码:

class BookParser(object):
    RATINGS = {
        'One': 1,
        'Two': 2,
        'Three': 3,
        'Four': 4,
        'Five': 5
    }
    
    def __init__(self, page):
        self.soup = BeautifulSoup(page, 'html.parser')

    def Content(self):
        return self.soup.find_all("li",attrs={"class": 'col-xs-6'})

    def getName(self):
        return self.soup.find('h3').find('a')['title']

    def getLink(self):
        return self.soup.find('h3').find('a')['href']
    
    def getPrice(self):
        locator = BookLocator.PRICE
        price = self.soup.select_one(locator).string
        
        pattern = r"[0-9\.]*"
        validator = re.findall(pattern, price)

        return float(validator[1])

    def getRating(self):
        locator = BookLocator.STAR_RATING
        rating = self.soup.select_one(locator).attrs['class']

        rating_number = BookParser.RATINGS.get(rating[1])
        return rating_number

最后,这是错误:

Traceback (most recent call last):
  File "c:\Users\Utkarsh Kumar\Documents\Projects\milestoneP4\app.py", line 13, in <module>
    name = container.getName()
TypeError: 'NoneType' object is not callable

我似乎不明白为什么getName()函数返回无类型。

任何帮助都将受到高度赞赏,因为我是Web抓取的新手。

PS:不用for循环就可以正常使用

类似这样的东西:

name = parser.getName()
print(name)

2 个答案:

答案 0 :(得分:2)

containers = parser.Content()为您提供BS4元素列表,而不是BookParser实例。您可以使用print(type(containers))进行验证。

要继续使用.getName(),您可以创建一个名为Book的新类,移动.getName并将所有相关方法移至该类,并传递从{{1}返回的列表项}方法(即.Content()),然后您可以调用li.col-xs-6

类似的事情应该起作用:

book.getName()

答案 1 :(得分:1)

列表中的每本书都包含在以下li元素中:

<li class="col-xs-6 col-sm-4 col-md-3 col-lg-3">
    <article class="product_pod">
       
            <div class="image_container">               
                    
                    <a href="catalogue/a-light-in-the-attic_1000/index.html"><img src="media/cache/2c/da/2cdad67c44b002e7ead0cc35693c0e8b.jpg" alt="A Light in the Attic" class="thumbnail"></a>
                       
            </div>
       
                <p class="star-rating Three">
                    <i class="icon-star"></i>
                    <i class="icon-star"></i>
                    <i class="icon-star"></i>
                    <i class="icon-star"></i>
                    <i class="icon-star"></i>
                </p>
            <h3><a href="catalogue/a-light-in-the-attic_1000/index.html" title="A Light in the Attic">A Light in the ...</a></h3>
            <div class="product_price">
        <p class="price_color">£51.77</p>   
<p class="instock availability">
    <i class="icon-ok"></i>  
        In stock
</p>
    
    <form>
        <button type="submit" class="btn btn-primary btn-block" data-loading-text="Adding...">Add to basket</button>
    </form>            
            </div>    
    </article>
</li>

很抱歉格式不正确,但是您明白了。创建一个在单个列表元素而不是整个对象汤对象上操作的类。例如:

class BookParser:
    def __init__(self, book_item ):
        self.book_item = book_item
    def getName( self ):
        return self.book_item.find( path_to_name ).text 

然后,您将首先解析页面,找到所有

  • 书籍元素,并使每个元素成为BookParser的实例。

    soup = BeautifulSoup( url )
    soup.find_all( path_to_book_elements )
    books = []
    for be in book_elements:
        books.append( BookParser( be ))
    books[0].getName() # A light in the Attic
    books[1].getName() # Tripping on Velvet