第4章:分支和循环——让代码学会“思考”和“重复”
写爬虫的时候,你会发现大部分时间不是在写新代码,而是在处理各种“意外情况”。比如:这个页面有没有加载出来?那个元素存不存在?数据要不要继续抓?
这时候,分支和循环就是你最好的朋友。它们让代码有了判断力,也有了耐力。
核心知识点一览:
- if判断语句:让代码做选择题
- 运算符:比较、逻辑、成员运算
- if-else / if-elif-else:多分支处理
- while循环:条件满足就一直干
- for循环:遍历一切可遍历的东西
- break / continue:控制循环的“刹车”和“跳过”
4.1 if判断语句:代码的“选择题”
说白了,if就是让代码做判断。条件成立,就执行里面的代码;不成立,就跳过。
# 最简单的if
status_code = 200
if status_code == 200:
print("请求成功,开始解析数据")
我在项目中遇到过一个问题:爬虫明明发了请求,却总是拿不到数据。后来一查,原来是状态码是302(重定向),我没做判断。从那以后,我每个请求都会先检查状态码。
我的习惯:写if的时候,先把条件写清楚,再写执行代码。别急着写逻辑,先想清楚“什么情况下该做什么”。
4.2 运算符:判断的“工具”
判断离不开运算符。常用的有三类:
| 类型 | 运算符 | 示例 | 说明 |
|---|---|---|---|
| 比较运算符 | ==, !=, >, <, >=, <= | a == b | 判断两个值的关系 |
| 逻辑运算符 | and, or, not | a > 0 and b < 10 | 组合多个条件 |
| 成员运算符 | in, not in | "python" in text | 判断是否在容器中 |
举个例子,爬虫里经常要判断某个关键词是否在页面里:
page_text = "Python爬虫实战教程"
if "爬虫" in page_text:
print("找到相关页面,开始提取链接")
else:
print("页面不相关,跳过")
注意:我曾经犯过一个低级错误——把 =(赋值)当成 ==(判断相等)来用。结果条件永远为真,程序跑飞了。记住:判断相等用两个等号!
4.3 if-else和if-elif-else:多分支处理
现实中的判断往往不止两个结果。比如爬虫遇到不同的状态码,处理方式完全不同:
status = response.status_code
if status == 200:
print("正常响应,解析数据")
elif status == 301 or status == 302:
print("页面重定向,需要跟进")
elif status == 404:
print("页面不存在,记录日志")
elif status == 503:
print("服务器繁忙,等待重试")
else:
print(f"未知状态码:{status},人工检查")
你想想看,如果没有这种多分支结构,你得写多少个if?代码会变得又臭又长。
避坑指南:我曾经在写爬虫时,把elif写成了if,结果每个条件都判断了一遍,导致同一个请求被处理了多次。记住:if-elif-else是“多选一”,而多个if是“多选多”。
4.4 while循环:条件满足就一直干
while循环的逻辑很简单:只要条件为真,就一直执行。适合用在“不知道要循环多少次”的场景。
# 模拟爬虫重试机制
retry_count = 0
max_retries = 3
while retry_count < max_retries:
print(f"第{retry_count + 1}次尝试请求...")
# 假设请求失败
success = False
if success:
print("请求成功!")
break
else:
retry_count += 1
print("请求失败,准备重试")
if retry_count == max_retries:
print("重试次数用尽,放弃该请求")
嗯,这里要注意:while循环最容易出问题的地方就是死循环。我刚开始学的时候,有一次忘记在循环里更新条件变量,结果程序卡死了,只能强制关闭。
警告:写while循环时,一定要确保条件最终会变成False。否则就是死循环,CPU会飙到100%。
4.5 for循环:遍历一切可遍历的东西
for循环是我用得最多的循环。它专门用来遍历序列——列表、元组、字典、字符串,甚至文件对象。
# 遍历列表
urls = ["page1.html", "page2.html", "page3.html"]
for url in urls:
print(f"正在抓取:{url}")
# 遍历字典
headers = {"User-Agent": "Mozilla", "Referer": "https://example.com"}
for key, value in headers.items():
print(f"{key}: {value}")
# 使用range()生成数字序列
for i in range(5):
print(f"第{i+1}页")
我个人习惯在爬虫里用for循环遍历URL列表,配合range做分页抓取。比如抓取10页数据:
for page in range(1, 11):
url = f"https://example.com/list?page={page}"
print(f"抓取第{page}页:{url}")
# 这里写具体的抓取逻辑
小技巧:range(start, stop, step)可以控制起始、结束和步长。比如range(0, 100, 10)会生成0, 10, 20, ..., 90。
4.6 break和continue:循环的“刹车”与“跳过”
这两个关键字,说白了就是用来控制循环流程的。
- break:立即终止整个循环,不再执行后续任何迭代
- continue:跳过当前这一次,直接进入下一次迭代
举个例子,爬虫里经常要“找到目标就停”或者“跳过无效数据”:
# break示例:找到目标就停止
target = "Python"
pages = ["Java", "C++", "Python", "JavaScript"]
for page in pages:
if page == target:
print(f"找到目标页面:{page}")
break # 找到了,后面的不用再找了
print(f"跳过:{page}")
# continue示例:跳过无效数据
data_list = [100, -1, 200, -1, 300]
for data in data_list:
if data == -1:
print("无效数据,跳过")
continue # 跳过本次,继续下一次
print(f"有效数据:{data}")
我记得有一次写爬虫,遇到大量重复的无效数据。如果不用continue,程序会一直处理这些垃圾数据,效率极低。加上continue后,直接跳过,速度提升了好几倍。
核心区别:break是“全剧终”,continue是“这一集跳过”。别搞混了。
4.7 实战组合:爬虫中的分支与循环
最后,我把今天讲的东西串起来,写一个简单的爬虫逻辑片段:
urls = ["https://example.com/1", "https://example.com/2", "https://example.com/3"]
max_retries = 3
for url in urls:
for attempt in range(max_retries):
print(f"请求 {url},第{attempt+1}次尝试")
# 模拟请求结果
status = 200 # 假设成功
if status == 200:
print(f"成功获取 {url}")
break # 成功就跳出重试循环
elif status == 503:
print("服务器忙,等待重试")
continue # 继续下一次重试
else:
print(f"其他错误,放弃 {url}")
break # 其他错误直接放弃
else:
# 这个else属于for循环,表示循环正常结束(没有被break)
print(f"重试全部失败,记录日志:{url}")
你看,分支和循环组合起来,就能写出健壮的爬虫代码。能处理成功、能处理失败、能重试、能跳过、能记录日志——这才是一个合格的爬虫工程师该写的代码。
我的建议:多练。把今天学的每个知识点都敲一遍,然后试着组合它们。写代码就像搭积木,分支和循环就是最基础的那几块。
可可精品资料库