# 【数据采集与融合技术】第二次大作业

## 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 代码及思路

#### 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):
"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:
data = urllib.request.urlopen(req)
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.4 心得体会

●SQL语言是一门嵌入式语言，可以嵌入其他高级语言

## 2.1 题目

• 要求：用requests和BeautifulSoup库方法定向爬取股票相关信息。

• 技巧：在谷歌浏览器中进入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.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：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格式，将其第一个大括号到最后一个大括号的内容提取出来才合法


#### 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.4 心得体会

●抓包过程中有很多名字一样的response，要点进f12功能【网络】面板的【预览】功能，查看response的url值对应的内容，一个个复制到浏览 器效率过低

●向数据库中写入中文的时候要注意要转换成utf-8的格式

●解析js文件的文本值即可以使用re库使用正则表达式匹配，也可以转换成json格式当成字典进行读取操作

## 3.1题目

• 作业③:

• 要求： 爬取中国大学2021主榜 https://www.shanghairanking.cn/rankings/bcur/2021
所有院校信息，并存储在数据库中，同时将浏览器F12调试分析的过程录制Gif加入至博客中。
• 技巧： 分析该网站的发包情况，分析获取数据的api
• 输出信息：
排名 学校 总分
1 清华大学 969.2

## 3.2 代码及思路

#### 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)


#### 3.2.4格式化输出并将数据插入数据库

for i in range(len(grade)):
tem=[]
tem.append("%d"%(i+1))
tem.append(name[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.4 心得体会

●一般网页会在打开时就把所有数据包装起来传给客户端，在翻页时直接在本地加载数据，所以要爬取有翻页功能的网站不一定要模拟翻页，也 可以尝试抓包获取数据文件

●正则表达式的模糊匹配功能强大，值得掌握

posted @ 2021-10-14 12:02  暴走小铸币  阅读(45)  评论(0编辑  收藏  举报