2023数据采集与融合技术实践作业二
作业①
(1)实验内容
o要求:在中国气象网(http://www.weather.com.cn)给定城市集的 7 日天气预报,并保存在数据库。
o输出信息:
序号 | 地区 | 日期 | 天气信息 | 温度 |
---|---|---|---|---|
1 | 北京 | 7日(今天) | 晴间多云,北部山区有阵雨或雷阵雨转晴转多云 | 31℃/17℃ |
2 | 北京 | 8日(明天) | 多云转晴,北部地区有分散阵雨或雷阵雨转晴 | 34℃/20℃ |
3 | 北京 | 9日(后台) | 晴转多云 | 36℃/22℃ |
4 | 北京 | 10日(周六) | 阴转阵雨 | 30℃/19℃ |
5 | 北京 | 11日(周日) | 阵雨 | 27℃/18℃ |
6...... |
oGitee 文件夹链接:
o核心代码:
创建数据库:
#天气数据库
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()
o运行结果:
o查询数据库:
(2)心得体会
这次实验对之前爬取天气的实例进行了复现,让我加深了对爬取网页的代码的学习,同时我还学会了如何创建一个数据库类,并且向数据库中插入数据,学会如何在pycharm中连接数据库,查看表格。
作业②
(1)实验内容
o要求:用 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
o输出信息:
oGitee 文件夹链接:
o实验步骤:
1.打开东方财富网( http://quote.eastmoney.com/center/gridlist.html#hs_a_board ),按下f12查看页面源代码,在network中寻找包含股票信息的js包,找到其头部url信息。
2.找到对应的地址,所有股票的信息都保存在了这个链接指向的对象中。
3.打开url查看:
可以发现,返回了20条股票信息,查看url的组成,存在一项“pz=20”的句子,大胆猜测这表示返回20条股票信息,如果改成111是否会返回更多数据呢?
尝试后,确实如假设所想,返回了111条股票数据(沪深京A股),至此,我们得到了数据的存放地址,可以通过修改pz值获取所需股票数据条数,通过requests库可以直接返回json数据。
o核心代码:
创建数据库:
# 股票数据库
class stockDB:
# 开启
def openDB(self):
self.con = sqlite3.connect("stocks.db")
self.cursor = self.con.cursor()
try:
self.cursor.execute("create table stocks (Num varchar(16), Code varchar(16),names varchar(16),Price varchar(16),Updown varchar(16),Updownnumber varchar(16),Trade varchar(16),Tradenumber varchar(16),Swing varchar(16),Highest varchar(16),Lowest varchar(16),Today varchar(16),Yesday varchar(16))")
except:
self.cursor.execute("delete from stocks")
# 关闭
def closeDB(self):
self.con.commit()
self.con.close()
# 插入
def insert(self,Num,Code,names,Price,Updown,Updownnumber,Trade,Tradenumber,Swing,Highest,Lowest,Today,Yesday):
try:
self.cursor.execute("insert into stocks(Num,Code,names,Price,Updown,Updownnumber,Trade,Tradenumber,Swing,Highest,Lowest,Today,Yesday) values (?,?,?,?,?,?,?,?,?,?,?,?,?)",
(Num,Code,names,Price,Updown,Updownnumber,Trade,Tradenumber,Swing,Highest,Lowest,Today,Yesday))
except Exception as err:
print(err)
正则表达式处理数据:
#通过正则表达式查找所需的所有数据
Code = re.findall('"f12":"(.*?)"', paper)
names = re.findall('"f14":"(.*?)"',paper)
Price = re.findall('"f2":(.*?),', paper)
Updown = re.findall('"f3":(.*?),', paper)
Updownnumber = re.findall('"f4":(.*?),', paper)
Trade = re.findall('"f5":(.*?),', paper)
Tradenumber = re.findall('"f6":(.*?),', paper)
Swing = re.findall('"f7":(.*?),', paper)
Highest = re.findall('"f15":(.*?),', paper)
Lowest = re.findall('"f16":(.*?),', paper)
Today = re.findall('"f17":(.*?),', paper)
Yesday = re.findall('"f18":(.*?),', paper)
#将数据加入列表进行后续处理
for i in range(len(Code)):
results.append([i+1,Code[i],names[i],Price[i],Updown[i],Updownnumber[i],Trade[i],Tradenumber[i],Swing[i],Highest[i],Lowest[i],Today[i],Yesday[i]])
o运行结果:
o查询数据库:
(2)心得体会
本次实验是第一尝试抓包并且通过json进行数据提取。在得到数据类型为json的数据后需要谨慎对数据进行处理,否则容易报错。这里我选择观察数据存放位置,通过正则表达式直接提取,存储。这次实验不仅加深了对之前爬取网页内容的学习,还学习了新的内容。
作业③
(1)实验内容
o要求:爬取中国大学 2021 主榜( https://www.shanghairanking.cn/rankings/bcur/2021 )所有院校信息,并存储在数据库中,同时将浏览器 F12 调试分析的过程录制 Gif 加入至博客中。
技巧:
分析该网站的发包情况,分析获取数据的 api
o输出信息:
排名 | 学校 | 省市 | 类型 | 总分 |
---|---|---|---|---|
1 | 清华大学 | 北京 | 综合 | 969.2 |
oGitee 文件夹链接:
o实验步骤:
1.打开网站( https://www.shanghairanking.cn/rankings/bcur/2021 ),按下f12,寻找要爬取信息对应的js包,以下为f12调试过程gif动图。
可以看到信息在一个 payload.js 的文件里,继续查看可以发现这里有582所学校的所有信息,说明网页显示的内容是通过 javascript 解析这个文件动态加载进去的,那么我们只要解析这个文件就可以了。
2.得到js包的URL地址后,打开url查看:
进去查看发现乱码,编写代码进行内容解析
o核心代码:
创建数据库:
#高校数据库
class collegeDB:
#开启
def openDB(self):
self.con = sqlite3.connect("colleges.db") # 连接数据库,没有的话会主动创建一个
self.cursor = self.con.cursor() # 设置一个游标
try:
self.cursor.execute("create table colleges(Rank varchar(16),univNameCn varchar(16),province varchar(16),univCategory varchar(16),score varchar(16))")
except:
self.cursor.execute("delete from colleges")
#关闭
def closeDB(self):
self.con.commit()
self.con.close()
#插入
def insert(self,Rank,univNameCn,province,univCategory,score):
try:
self.cursor.execute("insert into colleges(Rank,univNameCn,province,univCategory,score) values (?,?,?,?,?)", (Rank,univNameCn,province,univCategory,score))
except Exception as err:
print(err)
解析 js 文件内容:
文件内容格式不规则,里面既有类似 json 格式也有 JavaScript 的语法,所以不能直接用 json 进行解析。而且虽然信息是齐全的,但是里面有很多a,f,e,q,[i,l,j],ei,eg,ek...等字符信息,这些应该是某些信息的替代字符,类似函数中的形参。所以我们通过运用js2py,StringIO,redirect_stdout进行处理,并将其内容转化为字符串类型便于后续处理。
url = r'http://www.shanghairanking.cn/_nuxt/static/1695811954/rankings/bcur/2021/payload.js'
r = requests.get(url, timeout=20)
if r.status_code == 200:
r.encoding = 'utf-8'
html = r.text
#结合同学提供的方法,将js内容转换为字符串类型,方便后续运用正则表达式查找数据
js_function=html[len('__NUXT_JSONP__("/rankings/bcur/2021", ('):-3]
js_code=f"console.log({js_function})"
js=js2py.EvalJs()
pyf=js2py.translate_js(js_code)
f=StringIO()
with redirect_stdout(f):
exec (pyf)
s=f.getvalue()
正则表达式处理数据:
#运用正则表达式查找"学校", "省市", "类型", "总分"
r1 = "'univNameCn': '(.*?)'"
r2 = "'province': '(.*?)'"
r3 = "'univCategory': '(.*?)'"
r4 = "'score': (.*?),"
namelist = re.findall(r1, s, re.S | re.M)
provincelist=re.findall(r2, s, re.S | re.M)
univCategorylist=re.findall(r3, s, re.S | re.M)
scorelist = re.findall(r4, s, re.S | re.M)
o运行结果:
o查询数据库:
(2)心得体会
对payload.js进行处理的时候,不能直接用 JSON 进行解析的,因为这个文件中掺杂了 JavaScript 的代码,同时虽然信息是齐全的,但是里面有很多a,f,e,q,[i,l,j],ei,eg,ek...等字符信息,这些应该是某些信息的替代字符,这使得某些信息不能直接爬取。最后结合同学的方法进行处理,并将其内容转化为字符串类型便于后续正则表达式爬取。这次实验学会了另一种网页爬取方式,干货满满~~~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)