python循环爬取页面_使用for或while循环来处理处理不确定页数的网页数据爬取

本文介绍了使用Python的For循环和While循环来爬取页数不确定的网页,通过设置循环条件和判断终止标志,避免无用请求。以豌豆荚网站为例,展示了在Requests和Scrapy中两种循环的实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文转载自以下网站: Python For 和 While 循环爬取不确定页数的网页  https://www.makcyun.top/web_scraping_withpython16.html

需要学习的地方

有两种方法。

第一种方式 使用 For 循环配合 break 语句,尾页的页数设置一个较大的参数,足够循环爬完所有页面,爬取完成时,break 跳出循环,结束爬取。

第二种方法 使用 While 循环,可以结合 break 语句,也可以设起始循环判断条件为 True,从头开始循环爬取直到爬完最后一页,然后更改判断条件为 False 跳出循环,结束爬取。

Requests 和 Scrapy 中分别用 For 循环和 While 循环爬取不确定页数的网页。

摘要:Requests 和 Scrapy 中分别用 For 循环和 While 循环爬取不确定页数的网页。

我们通常遇到的网站页数展现形式有这么几种:

第一种是直观地显示所有页数,比如此前爬过的酷安、东方财富网,

文章见:

第二种是不直观显示网页总页数,需要在后台才可以查看到,比如之前爬过的虎嗅网,文章见:

第三种是今天要说的,不知道具体有多少页的网页,比如豌豆荚:

对于,前两种形式的网页,爬取方法非常简单,使用 For 循环从首页爬到尾页就行了,第三种形式则不适用,因为不知道尾页的页数,所以循环到哪一页结束无法判断。

那如何解决呢?有两种方法。

第一种方式 使用 For 循环配合 break 语句,尾页的页数设置一个较大的参数,足够循环爬完所有页面,爬取完成时,break 跳出循环,结束爬取。

第二种方法 使用 While 循环,可以结合 break 语句,也可以设起始循环判断条件为 True,从头开始循环爬取直到爬完最后一页,然后更改判断条件为 False 跳出循环,结束爬取。

实际案例

下面,我们以 豌豆荚 网站中「视频」类别下的 App 信息为例,使用上面两种方法抓取该分类下的所有 App 信息,包括 App 名称、评论、安装数量和体积。

首先,简要分析下网站,可以看到页面是通过 Ajax 加载的,GET 请求附带一些参数,可以使用 params 参数构造 URL 请求,但不知道一共有多少页,为了确保下载完所有页,设置较大的页数,比如 100页 甚至 1000 页都行。

下面我们尝试使用 For 和 While 循环爬取 。

Requests

▌For 循环

主要代码如下:

class Get_page():

def __init__(self):

# ajax 请求url

self.ajax_url = 'https://www.wandoujia.com/wdjweb/api/category/more'

def get_page(self,page,cate_code,child_cate_code):

params = {

'catId': cate_code,

'subCatId': child_cate_code,

'page': page,

}

response = requests.get(self.ajax_url, headers=headers, params=params)

content = response.json()['data']['content'] #提取json中的html页面数据

return content

def parse_page(self, content):

# 解析网页内容

contents = pq(content)('.card').items()

data = []

for content in contents:

data1 = {

'app_name': content('.name').text(),

'install': content('.install-count').text(),

'volume': content('.meta span:last-child').text(),

'comment': content('.comment').text(),

}

data.append(data1)

if data:

# 写入MongoDB

self.write_to_mongodb(data)

if __name__ == '__main__':

# 实例化数据提取类

wandou_page = Get_page()

cate_code = 5029 # 影音播放大类别编号

child_cate_code = 716 # 视频小类别编号

for page in range(2, 100):

print('*' * 50)

print('正在爬取:第 %s 页' % page)

content = wandou_page.get_page(page,cate_code,child_cate_code)

# 添加循环判断,如果content 为空表示此页已经下载完成了,break 跳出循环

if not content == '':

wandou_page.parse_page(content)

sleep = np.random.randint(3,6)

time.sleep(sleep)

else:

print('该类别已下载完最后一页')

break

这里,首先创建了一个 Get_page 类,get_page 方法用于获取 Response 返回的 json 数据,通过 json.cn 网站解析 json 解析后发现需要提取的内容是一段包裹在 data 字段下 content 键中的 html 文本,可以使用 parse_page 方法中的 pyquery 函数进行解析,最后提取出 App 名称、评论、安装数量和体积四项信息,完成抓取。

在主函数中,使用了 if 函数进行条件判断,若 content 不为空,表示该页有内容,则循环爬下去,若为空则表示此页面已完成了爬取,执行 else 分支下的 break 语句结束循环,完成爬取。

爬取结果如下,可以看到该分类下一共完成了全部 41 页的信息抓取。

▌While 循环

While 循环和 For 循环思路大致相同,不过有两种写法,一种仍然是结合 break 语句,一种则是更改判断条件。

总体代码不变,只需修改 For 循环部分:

page = 2 # 设置爬取起始页数

while True:

print('*' * 50)

print('正在爬取:第 %s 页' %page)

content = wandou_page.get_page(page,cate_code,child_cate_code)

if not content == '':

wandou_page.parse_page(content)

page += 1

sleep = np.random.randint(3,6)

time.sleep(sleep)

else:

print('该类别已下载完最后一页')

break

或者:

page = 2 # 设置爬取起始页数

page_last = False # while 循环初始条件

while not page_last:

#...

else:

# break

page_last = True # 更改page_last 为 True 跳出循环

结果如下,可以看到和 For 循环的结果是一样的。

我们可以再测试一下其他类别下的网页,比如选择「K歌」类别,编码为:718,然后只需要对应修改主函数中的child_cate_code 即可,再次运行程序,可以看到该类别下一共爬取了 32 页。

由于 Scrapy 中的写法和 Requests 稍有不同,所以接下来,我们在 Scrapy 中再次实现两种循环的爬取方式 。

Scrapy

▌For 循环

Scrapy 中使用 For 循环递归爬取的思路非常简单,即先批量生成所有请求的 URL,包括最后无效的 URL,后续在 parse 方法中添加 if 判断过滤无效请求,然后爬取所有页面。由于 Scrapy 依赖于Twisted框架,采用的是异步请求处理方式,也就是说 Scrapy 边发送请求边解析内容,所以这会发送很多无用请求。

def start_requests(self):

pages=[]

for i in range(1,10):

url='http://www.example.com/?page=%s'%i

page = scrapy.Request(url,callback==self.pare)

pages.append(page)

return pages

下面,我们选取豌豆荚「新闻阅读」分类下的「电子书」类 App 页面信息,使用 For 循环尝试爬取,主要代码如下:

def start_requests(self):

cate_code = 5019 # 新闻阅读

child_cate_code = 940 # 电子书

print('*' * 50)

pages = []

for page in range(2,50):

print('正在爬取:第 %s 页 ' %page)

params = {

'catId': cate_code,

'subCatId': child_cate_code,

'page': page,

}

category_url = self.ajax_url + urlencode(params)

pa = yield scrapy.Request(category_url,callback=self.parse)

pages.append(pa)

return pages

def parse(self, response):

if len(response.body) >= 100: # 判断该页是否爬完,数值定为100是因为response无内容时的长度是87

jsonresponse = json.loads(response.body_as_unicode())

contents = jsonresponse['data']['content']

# response 是json,json内容是html,html 为文本不能直接使用.css 提取,要先转换

contents = scrapy.Selector(text=contents, type="html")

contents = contents.css('.card')

for content in contents:

item = WandoujiaItem()

item['app_name'] = content.css('.name::text').extract_first()

item['install'] = content.css('.install-count::text').extract_first()

item['volume'] = content.css('.meta span:last-child::text').extract_first()

item['comment'] = content.css('.comment::text').extract_first().strip()

yield item

上面代码很好理解,简要说明几点:

第一、判断当前页是否爬取完成的判断条件改为了 response.body 的长度大于 100。

因为请求已爬取完成的页面,返回的 Response 结果是不为空的,而是有长度的 json 内容(长度为 87),其中 content 键值内容才为空,所以这里判断条件选择比 87 大的数值即可,比如 100,即大于 100 的表示此页有内容,小于 100 表示此页已爬取完成。

{"state":{"code":2000000,"msg":"Ok","tips":""},"data":{"currPage":-1,"content":""}}

第二、当需要从文本中解析内容时,不能直接解析,需要先转换。

通常情况下,我们在解析内容时是直接对返回的 response 进行解析,比如使用 response.css() 方法,但此处,我们的解析对象不是 response,而是 response 返回的 json 内容中的 html 文本,文本是不能直接使用 .css() 方法解析的,所以在对 html 进行解析之前,需要添加下面一行代码转换后才能解析。

contents = scrapy.Selector(text=contents, type="html")

结果如下,可以看到发送了全部 48 个请求,实际上该分类只有 22 页内容,即多发送了无用的 26 个请求。

▌While 循环

接下来,我们使用 While 循环再次尝试抓取,代码省略了和 For 循环中相同的部分:

def start_requests(self):

page = 2 # 设置爬取起始页数

dict = {'page':page,'cate_code':cate_code,'child_cate_code':child_cate_code} # meta传递参数

yield scrapy.Request(category_url,callback=self.parse,meta=dict)

def parse(self, response):

if len(response.body) >= 100: # 判断该页是否爬完,数值定为100是因为无内容时长度是87

page = response.meta['page']

cate_code = response.meta['cate_code']

child_cate_code = response.meta['child_cate_code']

#...

for content in contents:

yield item

# while循环构造url递归爬下一页

page += 1

params = {

'catId': cate_code,

'subCatId': child_cate_code,

'page': page,

}

ajax_url = self.ajax_url + urlencode(params)

dict = {'page':page,'cate_code':cate_code,'child_cate_code':child_cate_code}

yield scrapy.Request(ajax_url,callback=self.parse,meta=dict)

这里,简要说明几点:

第一、While 循环的思路是先从头开始爬取,使用 parse() 方法进行解析,然后递增页数构造下一页的 URL 请求,再循环解析,直到爬取完最后一页即可,这样 不会像 For 循环那样发送无用的请求。

第二、parse() 方法构造下一页请求时需要利用 start_requests() 方法中的参数,可以 使用 meta 方法来传递参数。

运行结果如下,可以看到请求数量刚好是 22 个,也就完成了所有页面的 App 信息爬取。

以上,就是本文的所有内容,小结一下:

在爬取不确定页数的网页时,可以采取 For 循环和 While 循环两种思路,方法大致相同。

在 Requests 和 Scrapy 中使用 For 循环和 While 循环的方法稍有不同,因此本文以豌豆荚网站为例,详细介绍了循环构造方法。

<think>好的,用户想学习如何用Python实现网页内容的多爬取并保存到CSV文件。我需要结合提供的引用内容,给出一个清晰的示例代码和步骤。首先,我得回顾一下用户提供的引用,看看哪些部分可以利用。 引用1提到使用BeautifulSoup解析网页和保存到CSV,引用2和3展示了保存数据的代码,引用4涉及翻处理,尤其是使用Selenium滑动页面和点击元素。用户的需求是多爬取,所以翻是关键。不过,引用4用的是Selenium,而引用1-3用的是Requests和BeautifulSoup。可能需要考虑两种方法:一种是处理带有翻参数的URL(比如查询参数page=),另一种是模拟浏览器点击,比如引用4的方法。 先考虑更常见的翻方式,比如URL中包含码的情况。这样可以通过循环改变码参数来实现多爬取,效率更高。不过有些网站可能需要JavaScript渲染,这时候可能需要Selenium。但用户的问题中没有特别说明网站类型,可能先以简单的Requests+BeautifulSoup为例,再提到Selenium的情况。 接下来,步骤应该包括:1. 分析网页结构,找到翻规律;2. 发送请求获取页面;3. 解析内容;4. 保存到CSV;5. 循环。 在示例代码中,需要导入requests、BeautifulSoup、csv等库。然后,构造分URL,比如在循环中生成每的链接。例如,base_url加上page参数。解析部分,需要提取所需数据,比如标题、价格等信息,这里可能需要根据目标网站调整选择器。保存数据时,使用csv.writerDictWriter,如引用2中的例子。 需要注意处理异常,比如请求失败、页面解析失败的情况,还有编码问题,如引用2中的encoding='utf-8'。此外,引用4提到随机等待时间,防止被封,所以在代码中可以加入time.sleep来延迟请求。 另外,用户可能需要处理反爬机制,比如设置headers中的User-Agent,如引用3中的headers。同时,引用4中的滑动到底部的操作可能用于动态加载的内容,但如果是静态分,可能不需要。 总结,示例代码结构大致如下: 1. 准备请求头,设置User-Agent。 2. 创建CSV文件,写入表头。 3. 循环码,构造URL。 4. 发送请求,检查响应状态。 5. 解析HTML,提取数据。 6. 写入CSV行。 7. 添加延迟,处理结束条件。 同时,需要提醒用户注意法律和网站规则,遵守robots.txt,不过度请求。 可能的问题:如何处理动态加载的翻按钮?这时候可能需要Selenium,如引用4中的方法。所以示例中可以分两种情况,一种是静态分,另一种是动态分,但用户的问题可能更关注静态的情况,所以先给出基于Requests的示例,再补充Selenium的方法作为扩展。 现在,编写示例代码,以爬取假设的电商网站商品列表为例,分参数为page,保存商品名称和价格到CSV。同时,处理循环,直到没有下一链接达到页数限制。 代码中需要包含异常处理,比如try-except块,以及随机延迟。还要注意CSV写入时的换行问题,如引用2中的newline=''参数。 最后,生成相关问题,可能涉及性能优化、反爬策略、数据清洗等。</think>### Python实现多爬取并保存CSV的步骤 #### 一、实现思路 1. **分析翻规律**:观察目标网站URL结构,如`page=2`等参数变化 2. **发送HTTP请求**:使用`requests`库获取网页内容,需添加请求头模拟浏览器访问 3. **解析网页内容**:通过`BeautifulSoup`提取结构化数据 4. **数据存储**:使用`csv`模块写入文件,注意编码和换行符处理 5. **循环控制**:设置码递增检测"下一"按钮实现翻 #### 二、示例代码 ```python import requests from bs4 import BeautifulSoup import csv import time import random # 请求头设置(防反爬) headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' } # 创建CSV文件 with open('products.csv', 'w', newline='', encoding='utf-8') as f: writer = csv.writer(f) writer.writerow(['商品名称', '价格']) # 写入表头 # 翻爬取(示例爬取3for page in range(1, 4): url = f'https://example.com/products?page={page}' try: response = requests.get(url, headers=headers) response.encoding = 'utf-8' if response.status_code != 200: print(f'第{page}请求失败') continue soup = BeautifulSoup(response.text, 'html.parser') items = soup.select('.product-item') # 根据实际网页结构调整选择器 for item in items: name = item.select_one('.title').text.strip() price = item.select_one('.price').text.replace('¥', '') writer.writerow([name, price]) print(f'第{page}抓取完成') time.sleep(random.uniform(1, 3)) # 随机延迟防封禁 except Exception as e: print(f'第{page}抓取出错:{str(e)}') ``` #### 三、关键代码说明 1. **分控制**:通过`page`参数循环生成不同码的URL 2. **随机延迟**:`time.sleep(random.uniform(1,3))`降低请求频率[^4] 3. **选择器调整**:`.product-item`等选择器需根据目标网站DOM结构修改 4. **编码处理**:`response.encoding`和文件`encoding='utf-8'`保证中文正常显示[^2] #### 四、动态翻场景 若网站使用JavaScript加载内容,需改用Selenium方案: ```python from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Chrome() try: while True: # 解析当前页数据... # 查找下一按钮 next_btn = driver.find_element(By.CSS_SELECTOR, '.next-page') if 'disabled' in next_btn.get_attribute('class'): break next_btn.click() time.sleep(3) # 等待页面加载 finally: driver.quit() ``` 该方法通过模拟点击实现翻,适用于无规律分参数的网站[^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值