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...等字符信息,这些应该是某些信息的替代字符,这使得某些信息不能直接爬取。最后结合同学的方法进行处理,并将其内容转化为字符串类型便于后续正则表达式爬取。这次实验学会了另一种网页爬取方式,干货满满~~~

posted @   一戴宗师  阅读(57)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示

目录导航