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

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

「数据采集」实验一

一、作业①

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可获取不同的数值,根据情况可删减请求的参数。

    参考链接:https://zhuanlan.zhihu.com/p/50099084

  • 输出信息:

序号 股票代码 股票名称 最新报价 涨跌幅 涨跌额 成交量 成交额 振幅 最高 最低 今开 昨收
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

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

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

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

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