Python 环境加载中…

翻页与礼貌地爬

3 道练习题·预计 50 分钟·做对一题解锁下一段

完整通读本章 →

教学 01 / 07· 已读

前言

上一章,咱们已经能把一页的 20 本书整整齐齐地取出来了。可是两点书店一共有 6 页,真实的网站更是动辄几十页、几百页。要是一页一页地手动去改网址,那就不叫爬虫了。

所以这一章,咱们要让爬虫自己翻页。办法有两种:一种是顺着页面上的「下一页」链接往下走,另一种是看出网址的规律,直接把每一页的地址拼出来。

能自己翻页了,请求也就跟着多了起来。这时候,第 1 章立下的规矩就要真正用起来了:每取一页,都要停一停。网站暂时出错了,就等一会儿再试,但别没完没了地试。循环要有出口,不能一直跑下去。

这些听上去都是小事,可真实的爬虫,很多就是栽在这些小事上:要么把网站拖垮了,要么被网站封掉了,要么半夜跑出一个死循环。所以写爬虫,慢一点不要紧,稳才是第一位的。

学这一章之前,需要先学完 爬虫课第 5 章 ,会用 parse_list() 把一页书取成列表,会用 urljoin() 补全链接。另外,还要熟悉基础课第 5 章的 while 循环和 break 。

目录

这一章会学到:

  • 一、顺着「下一页」往下翻——while 循环加出口
  • 二、看出网址规律,直接拼——先知道一共几页
  • 三、出错了怎么办——超时、重试和放弃
  • 四、常见坑
  • 五、自己查一次文档——怎么确认真的停了 0.2 秒
  • 六、小结与回看

学完这一章,你的爬虫能把整个书店的 120 本书一页不落地取下来,而且取得稳、取得有礼貌。

教学 02 / 07

一、顺着「下一页」往下翻

先说第一种办法:顺着「下一页」往下翻。两点书店每一页的底部,都有一个「下一页」的链接,只有最后一页没有。这个链接在 HTML 里长什么样呢?取回第 2 页,把底部的翻页栏打印出来看看:

Python· 可在网页运行
import requests
from bs4 import BeautifulSoup

soup = BeautifulSoup(requests.get('https://learn-py.org/lab/bookstore/page/2/').text, 'html.parser')
print(soup.select_one('nav.pager'))

输出的结果:

文本
<nav class="pager"><a class="prev" href="/lab/bookstore/page/1/">上一页</a><span class="current">2 / 6</span><a class="next" href="/lab/bookstore/page/3/">下一页</a></nav>

可以看到,翻页栏里有「上一页」,有当前是第几页,最后是一个 class 为 next 的链接。这个 a.next ,就是下一页的链接。

有了它,翻页的思路就清楚了:

  1. 取回当前页,把书取出来。
  2. 找 a.next 。找到了,就补全地址,作为下一轮要取的网页。找不到,说明已经到了最后一页,就停下来。

把这个思路写成代码,从首页开始一页一页往下取,顺便数一数一共取到了几本书:

Python· 可在网页运行
import time
from urllib.parse import urljoin

import requests
from bs4 import BeautifulSoup

url = 'https://learn-py.org/lab/bookstore/'
count = 0
while url:
    soup = BeautifulSoup(requests.get(url).text, 'html.parser')
    count = count + len(soup.select('article.book-card'))
    print(url, count)
    next_link = soup.select_one('a.next')
    url = urljoin(url, next_link['href']) if next_link else None
    time.sleep(0.2)
print(f'一共 {count} 本书')

输出的结果:

文本
https://learn-py.org/lab/bookstore/ 20
https://learn-py.org/lab/bookstore/page/2/ 40
https://learn-py.org/lab/bookstore/page/3/ 60
https://learn-py.org/lab/bookstore/page/4/ 80
https://learn-py.org/lab/bookstore/page/5/ 100
https://learn-py.org/lab/bookstore/page/6/ 120
一共 120 本书

6 页都取到了,一共 120 本书。那么,这个循环是怎么知道该停下来的呢?关键在 while url: ,和循环里找 next_link 的那两行:

  • while url: 的意思是:只要 url 不是 None ,就接着取。
  • 每取完一页,就去找 a.next 。找到了,url 就换成下一页的地址;找不到,url 就变成 None 。
  • 到了第 6 页,找不到 a.next ,url 变成了 None ,循环自然就停了。

这种写法还有一个好处:不用事先知道一共有几页。网站以后加了新的一页,也照样能取到。

下面先做一道练习:从第 4 页开始,顺着「下一页」一直翻到最后。

练习 1 / 3从第 4 页一直翻到最后题目有问题?

从第 4 页开始,顺着「下一页」链接(a.next )一页一页往下翻,直到最后一页。每取一页,打印这一页的地址和书的数量,并停 0.2 秒;最后打印一共取到几本。

运行后的输出应该是:

文本
https://learn-py.org/lab/bookstore/page/4/ 20
https://learn-py.org/lab/bookstore/page/5/ 20
https://learn-py.org/lab/bookstore/page/6/ 20
共 60 本
main.py
可编辑
做对当前题解锁下一段 ·03

推荐一个,全网最全最友好的中文 AI 编程指南: coding.stormzhang.ai

学习目录