python爬虫(十)BeautifulSoup案例分析

编程入门 行业动态 更新时间:2024-10-27 10:24:03

python<a href=https://www.elefans.com/category/jswz/34/1770264.html style=爬虫(十)BeautifulSoup案例分析"/>

python爬虫(十)BeautifulSoup案例分析

爬取全国天气

需求

从网站里爬取全国城市对应的最低温度,保存到csv文件里。
先要找到数据在哪,在页面点右键,检查网页源码,搜索“北京”,如下图

可以看到需要的数据在网页源码中,基本确定是静态加载出来的。我们向网页对应的url发起请求,就可以得到一串网页源码,用我们学到的方法进行解析就可以了,这样的话就可以确定目标url。

目标url

.shtml

页面分析

在页面表格城市“北京”处,点击右键,可以看到光标定位到<td 下的<a标签里,刚已经基本确定数据在网页源码中,虽然elements里的数据跟网页源码中有所区别,我们可以借助elements来进行页面分析和数据分析,定位的“北京”是在<td标签里面的,在往上折叠会发现他们都是存放于<tr标签中,前两个<tr代表的是表头,下面的每个<tr标签代表一个城市的数据,而所有的<tr标签都存放于<tbody标签里。<tbody是后来由网页渲染出来的,而在网页源码中搜索不到<tbody,不存在于网页源码中。<tbody标签存放于<table标签中,光标位于<table标签时,整个北京的数据都会被选中,再往上光标放到<div class="conMidtab2"时,不同的省/直辖市都会被选中;当光标定位到<div class="conMidtab"时,所有省/直辖市的表格都会被选中,而多个<div class="conMidtab"代表不同日期的天气情况。
从根目录往下展开,可以看到"海淀"位于,table --> tbody --> 第四个tr的文本(前两个tr是表头)的第一个td标签里;最低气温的20位于tr标签下倒数第二个td标签的文本里;我们可以用find找到第一个<div class="conMidtab"爬取第一天的天气,再用findall找到<div class="conMidtab"里所有<table标签,找到每个表格,在用findall找到所有的tr标签(过滤掉前两个tr),下面的每个tr代表的是一个城市的数据,而每个tr中的第一个td代表的是城市,倒数第二个td代表的是最低温度。
总结:

  1. 找到class="conMidtab"的div标签 里面存放了当天所有的的天气数据 用find
  2. 找到table标签 一个table对应一张表格 也就是一个省或者是直辖市的天气数据
  3. 找到table标签下面的所有tr 但是要过滤掉前两个tr标签(表头)
  4. 找到tr标签下面的所有的td 其中第一个td标签是城市名 倒数td第二个存放的是最低温
  5. 保存到csv文件中

工具:requests(发请求) bs4(解析数据) csv(保存数据)

实现步骤

import requests
from bs4 import BeautifulSoup
import csv
import time# 发送请求,获取相应
def req_data(url):headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 Edg/92.0.902.62'}res = requests.get(url, headers=headers)html = res.content.decode('utf-8')return html# 解析数据
def parse_data(html):soup = BeautifulSoup(html, 'lxml')# 1.找到class_="conMidtab"的div标签,只找一个div_class = soup.find(class_="conMidtab")# 2. 找到table标签,有好几个表格lis = []tables =div_class.find_all('table')for table in tables:# print(table)# 3.找到所有的tr标签,过滤掉前两个tr_tags = table.find_all('tr')[2:]for tr in tr_tags:d = {}#     print(tr)#     print('*'*50)# 4.在所有的tr标签下取出td标签tds = tr.find_all('td')# 其中第一个td标签是城市名,倒数td第二个存放的是最低温# 第一个td标签有两个文本,第一个是空格,所以用tds[0].stripped_strings) 返回的是生成器对象cities = list(tds[0].stripped_strings)[0]temps = list(tds[-2].stripped_strings)[0]# print(cities, temps)d['city'] = citiesd['temp'] = tempslis.append(d)# print(lis)return lis# 保存数据
def save_csv(lis, header):with open('weather.csv', 'a', encoding='utf-8', newline="") as f:writ = csv.DictWriter(f, header)if i == 0:   # 利用全局变量iwrit.writeheader()  # 只在第一页打印表头writ.writerows(lis)if __name__ == '__main__':# 把几个网页中不同的地方放到列表中,进行遍历取出,实现翻页处理lis1 = ['hb', 'db', 'hd', 'hz', 'hn', 'xb', 'xn', 'gat']global i  # 定义i为全局变量,实现去除重复表头for i in lis1:time.sleep(5)url = f'/{i}.shtml'h = req_data(url)lis = parse_data(h)header = ('city', 'temp')save_csv(lis, header)

程序运行完成之后,会出现每个表格(省/直辖市)的第一条数据显示的城市是省/直辖市的名字,比如河北省,第一条数据显示的是河北,而不是石家庄;山西省第一条数据显示的是山西,而不是大同。在网页源码中我们可以看到,经过过滤表头后,第一个td显示的是省/直辖市的名字,第二个td显示的是城市名字,所以要对每个表格判断一下,是否为第一条数据(城市),如果是就返回第二个td里的内容(因为第一个td显示的是省/直辖市),如果不是还是按照以前页面分析的返回第一个td标签(城市名),可以用enumerate()获取的索引值对获取到的td标签进行判断。

a = ['x', 'y', 'z']
# print(enumerate(a))  # 返回enumerate对象,<enumerate object at 0x000002AFB0E896C0>
# for i in enumerate(a):
#     print(i)  # 返回两个数据,第一个数据是元素的索引,第二个数据是元素本身for index, i in enumerate(a):print(index, i)# index接收到的是元素的索引值,0,1,2# i接收的是元素,x,y,z

可以对def parse_data()函数中for tr in tr_tags进行一下判断

         for index, tr in enumerate(tr_tags):d = {}#     print(tr)#     print('*'*50)# 4.在所有的tr标签下取出td标签tds = tr.find_all('td')# 其中第一个td标签是城市名,倒数td第二个存放的是最低温# 第一个td标签有两个文本,第一个是空格,所以用tds[0].stripped_strings) 返回的是生成器对象if index == 0:cities = list(tds[1].stripped_strings)[0]else:cities = list(tds[0].stripped_strings)[0]temps = list(tds[-2].stripped_strings)[0]

在最后一页,港澳台页面,显示的数据会有异常

这个时候回到网页源码中,查找<table标签,可以看到其实<table标签其实是不完整的,只有开头,没有结尾,这个时候就要把网页的解析器"lxml"换为"html5lib",这个解析器可以完善标签的内容,对所有残缺的标签进行补全,就是运行比较慢。

soup = BeautifulSoup(html, 'html5lib')


如果出现下图所示的内容 说明没有安装"html5lib",需要用pip install 安装一下就可以了

完整版代码如下:

import requests
from bs4 import BeautifulSoup
import csv
import time# 发送请求,获取相应
def req_data(url):headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 Edg/92.0.902.62'}res = requests.get(url, headers=headers)html = res.content.decode('utf-8')return html# 解析数据
def parse_data(html):soup = BeautifulSoup(html, 'html5lib')# 1.找到class_="conMidtab"的div标签,只找一个div_class = soup.find(class_="conMidtab")# 2. 找到table标签,有好几个表格lis = []tables =div_class.find_all('table')for table in tables:# print(table)# 3.找到所有的tr标签,过滤掉前两个tr_tags = table.find_all('tr')[2:]for index, tr in enumerate(tr_tags):d = {}#     print(tr)#     print('*'*50)# 4.在所有的tr标签下取出td标签tds = tr.find_all('td')# 其中第一个td标签是城市名,倒数td第二个存放的是最低温# 第一个td标签有两个文本,第一个是空格,所以用tds[0].stripped_strings) 返回的是生成器对象if index == 0:cities = list(tds[1].stripped_strings)[0]else:cities = list(tds[0].stripped_strings)[0]temps = list(tds[-2].stripped_strings)[0]# print(cities, temps)d['city'] = citiesd['temp'] = tempslis.append(d)# print(lis)return lis# 保存数据
def save_csv(lis, header):with open('weather.csv', 'a', encoding='utf-8', newline="") as f:writ = csv.DictWriter(f, header)if i == 0:   # 利用全局变量iwrit.writeheader()  # 只在第一页打印表头writ.writerows(lis)if __name__ == '__main__':# 把几个网页中不同的地方放到列表中,进行遍历取出,实现翻页处理lis1 = ['hb', 'db', 'hd', 'hz', 'hn', 'xb', 'xn', 'gat']global i  # 定义i为全局变量,实现去除重复表头for i in lis1:time.sleep(5)url = f'/{i}.shtml'h = req_data(url)lis = parse_data(h)header = ('city', 'temp')save_csv(lis, header)

更多推荐

python爬虫(十)BeautifulSoup案例分析

本文发布于:2024-02-27 14:40:28,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1706940.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:爬虫   案例分析   python   BeautifulSoup

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!