使用Python爬取Books to Scrape网站时遇AttributeError问题求助
错误根源分析
你的AttributeError是因为请求的书籍详情页URL错误,导致返回的页面不是书籍详情页,book_soup.find('ul', class_='breadcrumb')找不到对应元素,返回None后调用find_all就会报错。同时代码还有其他几个关键问题:
1. 缺失requests库导入
代码开头没有导入requests,运行时会先触发NameError,必须补上。
2. 书籍URL拼接错误
当前代码用url + book_url拼接,而url是分页地址(比如https://books.toscrape.com/catalogue/page-1.html),拼接后会变成无效地址(比如https://books.toscrape.com/catalogue/page-1.htmla-light-in-the-attic_1000/index.html),请求的页面根本不是书籍详情页,自然找不到面包屑导航元素。
正确的做法是用书籍目录的基础地址https://books.toscrape.com/catalogue/拼接book_url,或者用urllib.parse.urljoin自动处理相对路径。
3. 数据列表赋值错误
books_data = ([title, category, rating, price, availibility])是直接覆盖列表,而不是追加数据,最终只会保留最后一本书的信息,应该用books_data.append([...])。
4. 类名拼写错误
书籍库存的类名是availability,你写成了availibility,会导致find返回None,后续调用text也会报错。
修正后的代码
from bs4 import BeautifulSoup import requests # 补上缺失的导入 import csv import pandas as pd books_data = [] base_catalogue_url = 'https://books.toscrape.com/catalogue/' for page_num in range(1, 51): page_url = f'{base_catalogue_url}page-{page_num}.html' response = requests.get(page_url) soup = BeautifulSoup(response.content, 'html.parser') books = soup.find_all('h3') for book in books: book_relative_url = book.find('a')['href'] # 用基础目录地址拼接书籍相对URL book_full_url = base_catalogue_url + book_relative_url book_response = requests.get(book_full_url) book_soup = BeautifulSoup(book_response.content, 'html.parser') title = book_soup.find('h1').text # 先判断面包屑元素是否存在,避免报错 breadcrumb = book_soup.find('ul', class_='breadcrumb') if breadcrumb: category = breadcrumb.find_all('a')[2].text.strip() else: category = '未知分类' rating = book_soup.find('p', class_='star-rating')['class'][1] price = book_soup.find('p', class_='price_color').text.strip() # 修正类名拼写 availability = book_soup.find('p', class_='availability').text.strip() # 追加数据到列表 books_data.append([title, category, rating, price, availability]) print(books_data) # 也可以保存为CSV # pd.DataFrame(books_data, columns=['标题', '分类', '评分', '价格', '库存']).to_csv('books.csv', index=False)
额外优化建议
- 添加异常处理:比如请求失败时跳过该书籍,避免整个程序崩溃。
- 加入请求延迟:避免过快请求给服务器造成压力,比如
time.sleep(1)。 - 检查元素是否存在:比如获取评分、价格时,先判断
find的结果是否为None,再进行后续操作。
内容的提问来源于stack exchange,提问作者Mario Slavev

