2023数据采集与融合技术实践作业二
作业①:
要求:在中国气象网(http://www.weather.com.cn)给定城市集的 7日天气预报,并保存在数据库。
输出信息:
| 序号 | 地区 | 日期 | 天气信息 | 温度 |
|---|---|---|---|---|
| 1 | 北京 | 7日(今天) | 晴间多云,北部山区有阵雨或雷阵雨转晴转多云 | 31℃/17℃ |
| 2 | 北京 | 8日(明天) | 多云转晴,北部地区有分散阵雨或雷阵雨转晴 | 34℃/20℃ |
| 3 | 北京 | 9日(后台) | 晴转多云 | 36℃/22℃ |
| 4 | 北京 | 10日(周六) | 阴转阵雨 | 30℃/19℃ |
| 5 | 北京 | 11日(周日) | 阵雨 | 27℃/18℃ |
| 6...... |
Gitee 文件夹链接
1).代码:
from bs4 import BeautifulSoup
from bs4 import UnicodeDammit
import urllib.request
import sqlite3
class WeatherDB:
def openDB(self):
self.con=sqlite3.connect("weathers.db")
self.cursor=self.con.cursor()
try:
self.cursor.execute("create table weathers (wCity varchar(16),wDate varchar(16),wWeather varchar(64),wTemp varchar(32),constraint pk_weather primary key (wCity,wDate))")
except:
self.cursor.execute("delete from weathers")
def closeDB(self):
self.con.commit()
self.con.close()
def insert(self,city,date,weather,temp):
try:
self.cursor.execute("insert into weathers (wCity,wDate,wWeather,wTemp) values (?,?,?,?)" ,(city,date,weather,temp))
except Exception as err:
print(err)
def show(self):
self.cursor.execute("select * from weathers")
rows=self.cursor.fetchall()
print("%-16s%-16s%-32s%-16s" % ("city","date","weather","temp"))
for row in rows:
print("%-16s%-16s%-32s%-16s" % (row[0],row[1],row[2],row[3]))
class WeatherForecast:
def __init__(self):
self.headers = {
"User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9pre) Gecko/2008072421 Minefield/3.0.2pre"}
self.cityCode={"北京":"101010100","上海":"101020100","广州":"101280101","深圳":"101280601"}
def forecastCity(self,city):
if city not in self.cityCode.keys():
print(city+" code cannot be found")
return
url="http://www.weather.com.cn/weather/"+self.cityCode[city]+".shtml"
try:
req=urllib.request.Request(url,headers=self.headers)
data=urllib.request.urlopen(req)
data=data.read()
dammit=UnicodeDammit(data,["utf-8","gbk"])
data=dammit.unicode_markup
soup=BeautifulSoup(data,"lxml")
lis=soup.select("ul[class='t clearfix'] li")
for li in lis:
try:
date=li.select('h1')[0].text
weather=li.select('p[class="wea"]')[0].text
temp=li.select('p[class="tem"] span')[0].text+"/"+li.select('p[class="tem"] i')[0].text
print(city,date,weather,temp)
self.db.insert(city,date,weather,temp)
except Exception as err:
print(err)
except Exception as err:
print(err)
def process(self,cities):
self.db=WeatherDB()
self.db.openDB()
for city in cities:
self.forecastCity(city)
#self.db.show()
self.db.closeDB()
ws=WeatherForecast()
ws.process(["北京","上海","广州","深圳"])
print("completed")
结果:

2).心得体会:
第一个作业是对天气的复现作业,学习了如何创建与连接数据库、创建表,以及通过insert对表进行插入操作并且将表的内容打印出来。通过此次复现,对数据库有了一定的了解。
作业②:
要求:用 requests 和 BeautifulSoup 库方法定向爬取股票相关信息,并存储在数据库中。
候选网站:东方财富网:https://www.eastmoney.com/
新浪股票:http://finance.sina.com.cn/stock/
技巧:在谷歌浏览器中进入 F12 调试模式进行抓包,查找股票列表加载使用的 url,并分析 api 返回的值,并根据所要求的参数可适当更改api 的请求参数。根据 URL 可观察请求的参数 f1、f2 可获取不同的数值,根据情况可删减请求的参数。参考链接:https://zhuanlan.zhihu.com/p/50099084
输出信息:

Gitee 文件夹链接
首先通过f12进行抓包:

打开url查看:

1).代码:
利用request爬取数据并且通过json.loads提取数据:
for i in range(1, 10):
url = 'http://2.push2.eastmoney.com/api/qt/clist/get?cb=jQuery112407216976537918423_1695552655929&pn={}&pz=20&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&wbp2u=|0|0|0|web&fid=f3&fs=m:0+t:6,m:0+t:80,m:1+t:2,m:1+t:23,m:0+t:81+s:2048&fields=f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f12,f13,f14,f15,f16,f17,f18,f20,f21,f23,f24,f25,f22,f11,f62,f128,f136,f115,f152&_=1695552655930'.format(i)
r = requests.get(url)
r.raise_for_status()
html = r.text
# 去除非法字符
valid_json = html.strip()[len('jQuery112407216976537918423_1695552655929('):-1]
valid_json = valid_json[:-1]
# 转换为json
json_data = json.loads(valid_json)
data = json_data['data']['diff']
创建表:
cursor.execute('''
CREATE TABLE IF NOT EXISTS stocks (
id INTEGER PRIMARY KEY,
stock_code TEXT,
stock_name TEXT,
latest_price REAL,
change_percent REAL,
change_amount REAL,
volume REAL,
turnover REAL,
amplitude REAL,
highest REAL,
lowest REAL,
open_price REAL,
close_price REAL
)
''')
插入数据:
# 插入数据
for item in data:
cursor.execute('''
INSERT INTO stocks (
stock_code,
stock_name,
latest_price,
change_percent,
change_amount,
volume,
turnover,
amplitude,
highest,
lowest,
open_price,
close_price
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
''', (
item['f12'],
item['f14'],
item['f2'],
item['f3'],
item['f4'],
item['f5'],
item['f6'],
item['f7'],
item['f15'],
item['f16'],
item['f17'],
item['f18']
))
count += 1
输出数据:
# 打印数据
cursor.execute('SELECT * FROM stocks')
rows = cursor.fetchall()
for row in rows:
print(row)
结果:

2).心得体会:
本次实验是第一尝试抓包并且通过json进行数提取数据的,但最开始时遇到以下报错:

通过实验发现是因为url里面一些内容是非法字符,json无法解析,通过删除便解决了这个问题。
通过此次实验对抓包和数据库有了一定的了解。
作业③:
要求:爬取中国大学2021主榜(https://www.shanghairanking.cn/rankings/bcur/2021)所有院校信息,并存储在数据库中,同时将浏览器F12调试分析的过程录制Gif加入至博客中。
技巧:分析该网站的发包情况,分析获取数据的api
输出信息:
| 排名 | 学校 | 省市 | 类型 | 总分 |
|---|---|---|---|---|
| 1 | 清华大学 | 北京 | 综合 | 969.2 |
Gitee****文件夹链接
通过f12进行抓包:

先找到对应的payloads.js

点击进去虽然是乱码,但可以通过html.text进行解析

1).代码:
因为通过我的方法,省份和类型无法直接提取出来,所以需要先通过字典进行保存之后再进行映射:
# 创建省份和大学类别的字母映射字典
province_mapping = {
'k': '江苏','n': '山东', 'o': '河南','p': '河北','q': '北京','r': '辽宁','s': '陕西','t': '四川','u': '广东',
'v': '湖北','w': '湖南','x': '浙江','y': '安徽','z': '江西','A': '黑龙江','B': '吉林','C': '上海','D': '福建','E': '山西',
'F': '云南','G': '广西','I': '贵州','J': '甘肃','K': '内蒙古','L': '重庆','M': '天津','N': '新疆','Y': '海南'
}
univ_category_mapping = {
'f': '综合',
'e': '理工',
'h': '师范',
'm': '农业',
'T': '林业',
}
利用request和正则表达式进行数据提取:
url = 'https://www.shanghairanking.cn/_nuxt/static/1695811954/rankings/bcur/2021/payload.js'
header = {
"User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9pre) Gecko/2008072421 Minefield/3.0.2pre"
}
resp = requests.get(url, headers=header)
resp.raise_for_status()
resp.encoding = resp.apparent_encoding
html = resp.text
rname = 'univNameCn:"(.*?)"'
rscore = 'score:(.*?),'
rprovince = 'province:(.*?),'
runivCategory = 'univCategory:(.*?),'
namelist = re.findall(rname, html, re.S | re.M)
scorelist = re.findall(rscore, html, re.S | re.M)
provincelist = re.findall(rprovince, html, re.S | re.M)
univCategorylist = re.findall(runivCategory, html, re.S | re.M)
创建数据库与表:
# 创建或连接到数据库
conn = sqlite3.connect('university_rankings.db')
cursor = conn.cursor()
# 创建表格,如果不存在
cursor.execute('''
CREATE TABLE IF NOT EXISTS university_rankings (
rank INTEGER,
name TEXT,
province Text,
univCategory Text,
score REAL
)
''')
插入数据:
# 插入数据到数据库,将字母映射为具体内容
for rank, (name, province_letter, univCategory_letter, score) in enumerate(zip(namelist, provincelist, univCategorylist, scorelist), start=1):
try:
score_float = float(score)
except ValueError:
# 如果无法转换为浮点数,将分数设为 None
score_float = None
# 使用映射字典将字母替换为具体内容
province = province_mapping.get(province_letter, province_letter)
univCategory = univ_category_mapping.get(univCategory_letter, univCategory_letter)
cursor.execute("INSERT INTO university_rankings (rank, name, province, univCategory, score) VALUES (?, ?, ?, ?, ?)",
(rank, name, province, univCategory, score_float))
保存到excel中:
# 从数据库中检索数据
conn = sqlite3.connect('university_rankings.db')
cursor = conn.cursor()
cursor.execute("SELECT * FROM university_rankings")
data = cursor.fetchall()
conn.close()
# 创建一个DataFrame对象
df = pd.DataFrame(data, columns=["Rank", "Name", "Province", "UnivCategory", "Score"])
# 保存数据到Excel文件
excel_file = "university_rankings.xlsx" # 指定Excel文件名
df.to_excel(excel_file, index=False) # 将DataFrame保存为Excel文件,不包括索引列
print("数据已保存到 Excel 文件:", excel_file)
结果:

2).心得体会:
本次实验仍是抓包与数据库,但我将本题的结果从数据库中提取出来然后保存在excel中,通过此次实验,我更加深刻地理解了抓包与数据库、表的创建和数据的插入。
浙公网安备 33010602011771号