原代码:
import requests
import time
from lxml import etree
import random
from datetime import datetime
# 请求头
headers = {'user-agent': ' '}
# 设置url
url = 'https://www.cbaigui.com/'
i = 1
while True:
# 反馈信息
response = requests.get(url, headers=headers)
# 设置类型
response.encoding = 'utf8'
# 解析数据
html = etree.HTML(response.text)
# 提取名称列表、详情页面的url列表
names = html.xpath('//*[@id="page"]/div/div[1]/div/article/div/h2//text()')
# 去掉name列表中的空字符与换行符
names = [i.strip() for i in names if i.strip()]
# 详情页面的url列表
detail_urls = html.xpath('//*[@id="page"]/div/div[1]/div/article/div/h2//@href')
# 提取下一页url
next_url = html.xpath('//*[@id="page"]/div/div[1]/div/nav/div/a[@class="page larger"][1]//@href')[0]
# 遍历names,detail_url,获取页面url
for name, detail_url in zip(names, detail_urls):
# 反馈信息
response = requests.get(detail_url, headers=headers)
# 设置类型
response.encoding = 'utf8'
# 解析数据
html = etree.HTML(response.text)
# 提取描述内容
description = html.xpath('//*[@id="page"]/div/div[1]/div[2]/article/div/p/text()')
# 内容换行
description = '\n'.join(description)
# 写入文件
with open(f'cbaigui{datetime.now().strftime("%Y%m%d")}.txt', 'a', encoding='utf8') as f:
f.write(f'{i}、{name}\n{description}\n\n')
print(f'{i}、{name} 抓取成功')
i += 1
# 休眠间隔
time.sleep(random.randint(1, 3))
url = next_url
提取下一页url 的代码在写入文件之前
# 提取下一页url
next_url = html.xpath('//*[@id="page"]/div/div[1]/div/nav/div/a[@class="page larger"][1]//@href')[0]
原代码存在 爬取最后一页时 运行到提取下一页url的代码会报错,导致最后一页无法写入文件
所以我想把提取下一页url放在写入文件之后,实现即使报错,最后一页也已经爬取完毕,如下:
import requests
import time
from lxml import etree
import random
from datetime import datetime
# 请求头
headers = {'user-agent': ' '}
# 设置url
url = 'https://www.cbaigui.com/'
i = 1
while True:
# 反馈信息
response = requests.get(url, headers=headers)
# 设置类型
response.encoding = 'utf8'
# 解析数据
html = etree.HTML(response.text)
# 提取名称列表、详情页面的url列表
names = html.xpath('//*[@id="page"]/div/div[1]/div/article/div/h2//text()')
# 去掉name列表中的空字符与换行符
names = [i.strip() for i in names if i.strip()]
# 详情页面的url列表
detail_urls = html.xpath('//*[@id="page"]/div/div[1]/div/article/div/h2//@href')
# 遍历names,detail_url,获取页面url
for name, detail_url in zip(names, detail_urls):
# 反馈信息
response = requests.get(detail_url, headers=headers)
# 设置类型
response.encoding = 'utf8'
# 解析数据
html = etree.HTML(response.text)
# 提取描述内容
description = html.xpath('//*[@id="page"]/div/div[1]/div[2]/article/div/p/text()')
# 内容换行
description = '\n'.join(description)
# 写入文件
with open(f'cbaigui{datetime.now().strftime("%Y%m%d")}.txt', 'a', encoding='utf8') as f:
f.write(f'{i}、{name}\n{description}\n\n')
print(f'{i}、{name} 抓取成功')
i += 1
# 休眠间隔
time.sleep(random.randint(1, 3))
# 提取下一页url
next_url = html.xpath('//*[@id="page"]/div/div[1]/div/nav/div/a[@class="page larger"][1]//@href')[0]
url = next_url
但是运行到 提取下一页url这一行就会报错:IndexError: list index out of range
IndexError: list index out of range通常有两种情况
一个可能是下标超出范围,
一个可能是list是空的,没有一个元素
但我调试不出具体原因
您已经找到问题“元凶”了。报错就是下标溢出,由引用不存在的下标引发。
next_url = html.xpath('//*[@id="page"]/div/div[1]/div/nav/div/a[@class="page larger"][1]//@href')[0]
如果您 next_url == [] 时一定触发“下标溢出”错误。我这熟悉您的代码,因为我没学爬虫。😂您是不是可以用 string.join() 来获取列表中的字符串,这样子就不会因空列表而引发“下标溢出”报错了。
您可以去除语句末尾的下标引用 [] ,用 ''.join() ,用空字符连接列表内的所有字符串元素——
next_url = ''.join(html.xpath('//*[@id="page"]/div/div[1]/div/nav/div/a[@class="page larger"][1]//@href'))
或
next_url = html.xpath('//*[@id="page"]/div/div[1]/div/nav/div/a[@class="page larger"][1]//@href')
next_url = ''.join(next_url)
试试看。
import requests
from lxml import etree
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'}
for j in range(1,194):
res=requests.get(f'https://www.cbaigui.com/page{j}',headers=headers)
html = etree.HTML(res.text)
names = html.xpath('//*[@class="post-title"]/a//text()')
href=html.xpath('//*[@class="post-title"]/a/@href')
for i in range(len(names)):
print(names[i])
res=requests.get(href[i])
html = etree.HTML(res.text)
content = html.xpath('//*[@class="entry"]//text()')
print(content)