Python爬虫学习记录—— BooksToScrape分页爬取与图片下载 前面是踩坑和总结完整代码在最后目标网站为https://books.toscrape.com/主要内容分页爬取URL拼接CSV数据存储CSV读取图片下载常见编码错误处理一、分页爬取的核心思想直接写只能获取首页数据urlhttps://books.toscrape.com/resrequests.get(url)但网站实际上有50页数据。分页爬取的本质请求当前页 ↓ 解析数据 ↓ 找到下一页链接 ↓ 拼接URL ↓ 继续请求因此最终采用whileurl:# 请求页面# 解析数据# 获取下一页# 更新url二、不要手动拼接URL这是我最开始写法next_urlurlnext_href例如base_urlhttps://books.toscrape.com/next_hrefpage-3.html得到https://books.toscrape.com/page-3.html这是错误的。因为当前页面实际上位于https://books.toscrape.com/catalogue/page-2.html正确地址应该是https://books.toscrape.com/catalogue/page-3.html解决方案fromurllib.parseimporturljoin next_urlurljoin(url,next_href)以后遇到.././/path等相对路径时都能自动处理。三、next按钮不存在时的错误最开始写法next_hrefsoup.find(li,class_next).find(a)[href]当最后一页没有next按钮时soup.find(li,class_next)返回None程序报错AttributeError:NoneTypeobjecthas no attributefind正确写法next_lisoup.find(li,class_next)ifnext_liisNone:breaknext_hrefnext_li.find(a)[href]四、CSV写入位置问题错误写法whileurl:withopen(books.csv,w)asf:writer.writerow(...)问题每次循环都会重新创建文件。结果第一页数据被覆盖 第二页数据被覆盖 第三页数据被覆盖 ...最后只剩最后一页。正确写法withopen(books.csv,w,newline,encodingutf-8-sig)asf:writercsv.writer(f)writer.writerow([书名,价格,库存,封面])whileurl:writer.writerow(...)文件只打开一次。五、CSV编码问题保存时withopen(books.csv,w,encodingutf-8-sig)从csv文件读取内容不要忘记指定编码withopen(books.csv,r)导致UnicodeDecodeError原因Windows默认使用GBK读取。而文件实际编码utf-8-sig解决withopen(books.csv,r,encodingutf-8-sig)读写编码必须一致。六、enumerate的使用fori,iteminenumerate(data,start1):pass优点代码更简洁自动计数可指定起始值例如fori,iteminenumerate(reader,start1):得到1 2 3 ...七、下载图片读取CSV中的图片地址readercsv.DictReader(f)forrowinreader:img_urlrow[封面]下载resrequests.get(img_url,headersheaders,proxiesproxy,timeout10)保存withopen(filename,wb)asfile:file.write(res.content)注意wb表示二进制写入。图片、视频等文件都要使用wb八、限制下载前10张图片实现fori,rowinenumerate(reader,start1):ifi10:break只下载image_1.png image_2.png ... image_10.png用于测试非常方便。九、本次项目最终结构请求首页 ↓ 解析书籍数据 ↓ 写入CSV ↓ 寻找下一页 ↓ 翻页 ↓ 保存全部数据 ↓ 读取CSV ↓ 下载图片已经完成✅ Requests基础使用✅ BeautifulSoup解析✅ 分页爬取✅ URL拼接✅ CSV存储✅ CSV读取✅ 图片下载十、完整代码importrequestsfromurllib.parseimporturljoinfrombs4importBeautifulSoupimportcsvimportos urlhttps://books.toscrape.com/#代理端口改成自己的proxy{http:http://127.0.0.1:7892,https:http://127.0.0.1:7892}headers{User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36,Accept:text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8,Accept-Language:zh-CN,zh;q0.9,en;q0.8,Accept-Encoding:gzip, deflate, br,Connection:keep-alive}defget_books():globalurl num0withopen(book_1.csv,w,newline,encodingutf-8-sig)asf:writercsv.writer(f)writer.writerow([书名,价格,库存,封面])whileurl:num1resrequests.get(url,proxiesproxy,headersheaders,timeout10)soupBeautifulSoup(res.text,html.parser)#解析书籍articlessoup.find_all(article,class_product_pod)forarticleinarticles:titlearticle.find(h3).find(a)[title]pricearticle.find(p,class_price_color).text.strip()instockarticle.find(p,class_instock availability).text.strip()img_urlurljoin(url,article.find(img)[src])writer.writerow([title,price,instock,img_url])print(f当前第{num}页数据写入完成)#找next没有直接退出next_lisoup.find(li,class_next)ifnext_liisNone:print(爬取完成)breaknext_urlnext_li.find(a)[href]urlurljoin(url,next_url)#保存图片defsave_image():makedirdownos.makedirs(makedir,exist_okTrue)withopen(book_1.csv,r,encodingutf-8-sig)asf:readercsv.DictReader(f)fori,readinenumerate(reader,start1):img_urlread[封面]resrequests.get(img_url,headersheaders,proxiesproxy,timeout10)ifi10:print(保存成功)breakfilenameos.path.join(makedir,fimage_{i}.png)withopen(filename,wb)asfile:file.write(res.content)if__name____main__:get_books()save_image()