【数据采集与融合技术】第二次大作业
【数据采集与融合技术】第二次大作业
「数据采集」实验一
一、作业①
1.1 题目
-
要求:在中国气象网(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......
1.2 代码及思路
●码云链接:2/1.py · 灰色/2019级数据采集与融合技术 - 码云 - 开源中国 (gitee.com)
1.2.1 创建数据库类WeatherDB
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))") #cursor.execute()可执行sql语句
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]))
1.2.2 创建爬虫类WeatherForecast
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 = {"北京": "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()
1.2.3 主函数
ws = WeatherForecast()
ws.process(["北京", "上海", "广州", "深圳"])
print("completed")
1.3 运行结果
1.3.1 控制台输出
1.3.2 sqlite3数据库可视化
采用sqliteStudio进行可视化
1.4 心得体会
●SQL语言是一门嵌入式语言,可以嵌入其他高级语言
二、作业②
2.1 题目
-
要求:用requests和BeautifulSoup库方法定向爬取股票相关信息。
-
候选网站:东方财富网:http://quote.eastmoney.com/center/gridlist.html#hs_a_board
-
技巧:在谷歌浏览器中进入F12调试模式进行抓包,查找股票列表加载使用的url,并分析api返回的值,并根据所要求的参数可适当更改api的请求参数。根据URL可观察请求的参数f1、f2可获取不同的数值,根据情况可删减请求的参数。
-
输出信息:
序号 | 股票代码 | 股票名称 | 最新报价 | 涨跌幅 | 涨跌额 | 成交量 | 成交额 | 振幅 | 最高 | 最低 | 今开 | 昨收 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 688093 | N世华 | 28.47 | 62.22% | 10.92 | 26.13万 | 7.6亿 | 22.34 | 32.0 | 28.08 | 30.2 | 17.55 |
2...... |
2.2 代码及思路
●码云链接:2/2.py · 灰色/2019级数据采集与融合技术 - 码云 - 开源中国 (gitee.com)
2.2.1 准备工作
进入东方财富网观察页面
进入【沪深指数】界面,打开浏览器的F12功能并刷新页面,打开【网络】面板尝试抓包
由【secid】属性的对应关系,推断该js对象应该是个股的数据
将url复制放进浏览器,打开页面如下
多次尝试找到整个页面数据对应的js对象
将url复制放进浏览器,打开页面如下
接下来开始爬取
2.2.2 数据库操作类
#数据库类
class GPDB:
def openDB(self):
self.con=sqlite3.connect("hsjgp.db")
self.cursor=self.con.cursor()
try:
self.cursor.execute("create table hsjgp (序号 varchar(8),股票代码 varchar(16),股票名称 varchar(16),最新报价 varchar(32),涨跌幅 varchar(32),涨跌额 varchar(32),成交量 varchar(32),成交额 varchar(32),振幅 varchar(32),最高 varchar(32),最低 varchar(32),今开 varchar(32),昨收 varchar(32))")#sqlite3支持中文字段名
except:
self.cursor.execute("delete from hsjgp")
def closeDB(self):
self.con.commit()
self.con.close()
def insert(self, var1,var2,var3,var4,var5,var6,var7,var8,var9,var10,var11,var12,var13):
try:
self.cursor.execute("insert into hsjgp (序号,股票代码,股票名称,最新报价,涨跌幅,涨跌额,成交量,成交额,振幅,最高,最低,今开,昨收) values (?,?,?,?,?,?,?,?,?,?,?,?,?)",
(var1,var2,var3,var4,var5,var6,var7,var8,var9,var10,var11,var12,var13))
except Exception as err:
print(err)
2.2.3 将目标字符串转为json格式
这里将访问url返回的二进制码转为字符串后,用json.loads()的方式将字符串转成字典,字典的["data"]下的["diff"]就是所有股票的列表
#抓包获得初始url:pn属性控制翻页,f1,f2,f152分别是股票的参数
url="http://26.push2.eastmoney.com/api/qt/clist/get?" \
"cb=jQuery11240342740870181792_1634086613552&" \
"pn=%d&pz=50&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&" \
"invt=2&fid=&fs=b:MK0010&" \
"fields=f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f12,f13,f14,f15,f16,f17," \
"f18,f20,f21,f23,f24,f25,f26,f22,f11,f62,f128,f136,f115,f152&_=1634086613557"
newurl=url%(1)
r=requests.get(newurl)
r.encoding = "UTF-8"
myjson=r.text[r.text.index("(")+1:-3] #爬取的字符串不符合json格式,将其第一个大括号到最后一个大括号的内容提取出来才合法
myjson=json.loads(myjson+"}") #将字符串转为字典
2.2.4 爬取目标内容并保存到数据库中
output=[]
for i in range(len(myjson['data']['diff'])):
data=myjson['data']['diff'][i]
tem=[]
tem.append("%d"%i)
tem.append(data['f12'])
tem.append(data['f14'])
tem.append(data['f2'])
tem.append(data['f3'])
tem.append(data['f4'])
tem.append(data['f5'])
tem.append(data['f6'])
tem.append(data['f7'])
tem.append(data['f15'])
tem.append(data['f16'])
tem.append(data['f17'])
tem.append(data['f18'])
db.insert(tem[0],tem[1],tem[2],tem[3],tem[4],tem[5],tem[6],tem[7],tem[8],tem[9],tem[10],tem[11],tem[12])
output.append(tem)
2.2.5 格式化输出
# 计算有多少个中文字符,输出格式用到
def count(s):
return len([ch for ch in s if '\u4e00' <= ch <= '\u9fff'])
#格式化输出函数
def printUnivList(ulist, num):
temp = "{:<5} {:<8} {:<"+str(10-count(data['f14']))+"} {:<7} {:<7} {:<7} {:<8} {:<13} {:<6} {:<6} {:<6} {:<6} {:<6}"
for i in range(num):
u = ulist[i]
print(temp.format(u[0], u[1], u[2], u[3],u[4], u[5], u[6], u[7],u[8], u[9], u[10], u[11],u[12]))
print("{:<3} {:<5} {:<6} {:<4} {:<5} {:<5} {:<8} {:<9} {:<4} {:<5} {:<4} {:<5} {:<5}".format("序号", "股票代码", "股票名称", "最新报价", "涨跌幅", "涨跌额", "成交量", "成交额", "振幅", "最高", "最低", "今开", "昨收"))
printUnivList(output, len(output))
2.3运行结果
2.3.1 控制台输出
2.3.2 sqlite3数据库可视化
采用sqliteStudio进行可视化
2.4 心得体会
●抓包过程中有很多名字一样的response,要点进f12功能【网络】面板的【预览】功能,查看response的url值对应的内容,一个个复制到浏览 器效率过低
●向数据库中写入中文的时候要注意要转换成utf-8的格式
●解析js文件的文本值即可以使用re库使用正则表达式匹配,也可以转换成json格式当成字典进行读取操作
●json.loads()方法默认将中文解析为Unicode码,可以将ensure_ascii设为False来保留原有的中文
三、作业③
3.1题目
-
作业③:
- 要求: 爬取中国大学2021主榜 https://www.shanghairanking.cn/rankings/bcur/2021
所有院校信息,并存储在数据库中,同时将浏览器F12调试分析的过程录制Gif加入至博客中。 - 技巧: 分析该网站的发包情况,分析获取数据的api
- 输出信息:
排名 学校 总分 1 清华大学 969.2 - 要求: 爬取中国大学2021主榜 https://www.shanghairanking.cn/rankings/bcur/2021
3.2 代码及思路
3.2.1 准备工作
抓包过程如下
3.2.2 数据库操作类
class UNIDB:
def openDB(self):
self.con=sqlite3.connect("hsjuni.db")
self.cursor=self.con.cursor()
try:
self.cursor.execute("create table hsjuni (排名 varchar(8),学校名称 varchar(32),总分 varchar(16))")
except:
self.cursor.execute("delete from hsjuni")
def closeDB(self):
self.con.commit()
self.con.close()
def insert(self, var1,var2,var3):
try:
self.cursor.execute("insert into hsjuni (排名,学校名称,总分) values (?,?,?)",
(var1,var2,var3))
except Exception as err:
print(err)
3.2.3 正则表达式匹配学校名称和总分
name=re.findall(r'univNameCn:"(.*?)"',demo)
grade=re.findall(r'score:(.*?),',demo)
发现有的学校分数是乱码,可能是网页源码有误
3.2.4格式化输出并将数据插入数据库
for i in range(len(grade)):
tem=[]
tem.append("%d"%(i+1))
tem.append(name[i])
tem.append(grade[i])
db.insert(tem[0],tem[1],tem[2])
output.append(tem)
db.closeDB()
print('{0:^10}{1:^22}{2:^20}'.format('排名','学校名称','分数'))
printUnivList(output,len(output))
3.3 运行结果
3.3.1 控制台输出
3.3.2 sqlite3数据库可视化
采用sqliteStudio进行可视化
3.4 心得体会
●一般网页会在打开时就把所有数据包装起来传给客户端,在翻页时直接在本地加载数据,所以要爬取有翻页功能的网站不一定要模拟翻页,也 可以尝试抓包获取数据文件
●正则表达式的模糊匹配功能强大,值得掌握