数据采集与融合第二次作业——董婕
作业1
要求
在中国气象网(http://www.weather.com.cn)给定城市集的 7日天气预报,并保存在数据库
输出信息

gitee链接
https://gitee.com/djj031217/djj/blob/master/数据采集与融合技术第二次作业/实验2 1.py
实现过程
在搜索框搜索想要查找的城市

点进去后在这里可以找到各个城市与数字的对应关系,将其添加到代码中即可。

代码
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 NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362"}
# "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 = {"安徽": "101220101", "黄山": "101221001", "广州": "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
要求
- 用 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链接
https://gitee.com/djj031217/djj/blob/master/数据采集与融合技术第二次作业/实验2 2.py
实现过程
观察数据结构可发现
- 参数pn会随着页数的增加而增加,故pn即页码
- fields参数对应的是列信息
- 同一只股票的fs相同,fs代表的是股票信息
代码
import requests
import re
import xlsxwriter
# 定义函数,用于获取页面数据
def getHTML(fs, page):
pz = 20
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"
url = "http://58.push2.eastmoney.com/api/qt/clist/get?cb=jQuery112409968248217612661_1601548126340&pn=" + str(page) + \
"&pz=" + str(pz) + "&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&fid=f3&fs=" + fs["沪深A股"] + \
"&fields=" + fields + "&_=1601548126345"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36 Edg/85.0.564.63"}
try:
res = requests.get(url, headers=headers)
pat = '"diff":\[(.*?)\]'
data = re.compile(pat, re.S).findall(res.text)
datas = data[0].split("},{")
return datas
except:
print('wrong url')
# 定义函数,用于创建Excel文件的标题行
def create_Header(workbook):
worksheet = workbook.add_worksheet()
bold = workbook.add_format({'bold': True, 'font_color': 'red', 'align': 'center'})
worksheet.write('A1', '代码', bold)
worksheet.write('B1', '名称', bold)
worksheet.write('C1', '最新价', bold)
worksheet.write('D1', '涨跌幅', bold)
worksheet.write('E1', '涨跌额', bold)
worksheet.write('F1', '成交量', bold)
worksheet.write('G1', '成交额', bold)
worksheet.write('H1', '涨幅', bold)
worksheet.set_column('A:A', 10)
worksheet.set_column('B:B', 10)
worksheet.set_column('C:C', 8)
worksheet.set_column('D:D', 8)
worksheet.set_column('E:E', 8)
worksheet.set_column('F:F', 10)
worksheet.set_column('G:G', 16)
worksheet.set_column('H:H', 8)
return worksheet
# 定义函数,用于将页面数据写入Excel文件
def getPageData(datas, row):
col = 0
for i in range(len(datas)):
datas1 = datas[i].split(",")
Number = eval(datas1[11].split(":")[1])
Name = eval(datas1[13].split(":")[1])
Newest_price = eval(datas1[1].split(":")[1])
updownExtent = eval(datas1[2].split(":")[1])
updownValue = eval(datas1[3].split(":")[1])
Money_number = eval(datas1[4].split(":")[1])
Money = eval(datas1[5].split(":")[1])
Up_number = eval(datas1[6].split(":")[1])
worksheet.write(row, col, Number)
worksheet.write(row, col + 1, Name)
worksheet.write(row, col + 2, Newest_price)
worksheet.write(row, col + 3, updownExtent)
worksheet.write(row, col + 4, updownValue)
worksheet.write(row, col + 5, Money_number)
worksheet.write(row, col + 6, Money)
worksheet.write(row, col + 7, Up_number)
row += 1
if __name__ == '__main__':
fs = {
"沪深A股": "m:0+t:6,m:0+t:13,m:0+t:80,m:1+t:2,m:1+t:23"
}
page = 4
row = 1
name = "股票"
workbook = xlsxwriter.Workbook(name + '.xlsx')
worksheet = create_Header(workbook)
for p in range(page):
datas = getHTML(fs, p + 1)
getPageData(datas, row)
row += 20
print("\n存储成功!")
workbook.close()
print("\n爬取结束")
结果

心得
本次作业与之前不太一样,东方财富网页面所包含的股票信息被分成了多个板块,我们无法直接通过网页的url爬取所有数据,故本题采用动态抓包,使用f12进行抓包抓取json并分析得到数据对应的url。
作业3
要求
- 爬取中国大学 2021 主榜( https://www.shanghairanking.cn/rankings/bcur/2021 )所有院校信息,并存储在数据库中,同时将浏览器 F12 调试分析的过程录制 Gif 加入至博客中。
- 技巧:分析该网站的发包情况,分析获取数据的 api
输出信息

gitee链接
https://gitee.com/djj031217/djj/blob/master/数据采集与融合技术第二次作业/实验2 3.py
实现过程
演示视频

很容易找到学校名称和分数的信息,但省份和学校类别的信息是在头尾的键值对里的,一开始没注意,找了挺久的。
故需要添加键值对的映射,省份和类别映射如下
category = {
'e': '理工',
'f': '综合',
'h': '师范',
'm': '农业',
'T': '林业',}
province = {
'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': '海南'
}
代码
import re
import requests
import pandas as pd
import pymysql
# 创建大学类别的字母映射字典
category = {
'f': '综合',
'e': '理工',
'h': '师范',
'm': '农业',
'T': '林业',
}
# 创建省份字母映射字典
province = {
'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': '海南'
}
url = 'https://www.shanghairanking.cn/_nuxt/static/1697106492/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
# 编译正则表达式
obj = re.compile(
r'univNameCn:"(?P<univNameCn>.*?)",.*?'
r'univCategory:(?P<univCategory>.*?),.*?'
r'province:(?P<province>.*?),'
r'score:(?P<score>.*?),'
, re.S)
result1 = obj.finditer(resp.text)
results = []
# 遍历正则匹配的结果
for idx, it in enumerate(result1, start=1):
univNameCn = it.group('univNameCn')
univCategory = it.group('univCategory')
province_code = it.group('province')
score = it.group('score')
# 使用字典进行映射转换
mapped_province = province.get(province_code, province_code) # 如果找不到映射,则使用原始值
mapped_category = category.get(univCategory, univCategory) # 如果找不到映射,则使用原始值
results.append((idx, univNameCn, mapped_province, mapped_category, score))
# 使用pandas创建DataFrame
df = pd.DataFrame(results, columns=['排名', '学校', '省市', '类型', '总分'])
# 连接到MySQL数据库
db = pymysql.connect(host='localhost', user='root', password='1', database='dong')
cursor = db.cursor()
# 将DataFrame中的数据插入到MySQL数据库表中
for index, row in df.iterrows():
sql = "INSERT INTO 22 (排名, 学校, 省市, 类型, 总分) VALUES (%s, %s, %s, %s, %s)"
cursor.execute(sql, (row['排名'], row['学校'], row['省市'], row['类型'], row['总分']))
# 提交更改并关闭数据库连接
db.commit()
db.close()
# 保存DataFrame为Excel文件
df.to_excel('universities.xlsx', index=False)
结果
在navicat储存

心得
1.学会了一种新的方式获取数据,先抓包,再分析包中的数据。
2.重新复习了mysql的一些语法,并意识到要仔细观察数据结构,比如前后的键值对映射关系

浙公网安备 33010602011771号