数据采集第二次作业

作业一

  要求:在中国气象网(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......      

作业过程

分析网页

在谷歌浏览器中输入url,f12进入开发者模式,进行网页分析。

 查找网页html元素,发现需要爬取的数据可以直接找到,分析网页,网页标签树十分清晰,采用bs库进行解析或许会比较快速。

代码部分

定义类创建数据表:

class WeatherDB:
    def openDB(self):#创建表并定义表
        self.con = sqlite3.connect("weathers.db")
        self.cursor = self.con.cursor()
        try:
            self.cursor.execute("create table weathers (wnum varchar(8),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,num,city,date,weather,temp):#插入数据
        try:
            self.cursor.execute("insert into weathers (wnum,wCity,wDate,wWeather,wTemp) values (?,?,?,?,?)",(num,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%-16s%-32s%-16s" % ("num","city", "date", "weather", "temp"))#表头
        for row in rows:
            print("%-16s%-16s%-16s%-32s%-16s" % (row[0],row[1],row[2],row[3],row[4]))

定义类获取网页html爬取数据并保存到本地db文件中

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):#爬取网页信息并保存到数据库中
        #city参数是某一个城市
        if city not in self.cityCode.keys():
            print(city+" code cannot be found")
            return
        global num
        url = "http://www.weather.com.cn/weather/" + self.cityCode[city] + ".shtml"#获取html
        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")#bs分析网页树
            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']")[0].text.strip()
                    self.db.insert( num, city, date, weather, temp)#插入到数据库中
                    num = num + 1
                except Exception as err:
                    print(err)
        except Exception as err:
            print(err)

    def process(self, cities):
        self.db = WeatherDB()  # 创建天气数据库对象,db
        self.db.openDB()  # 打开数据库

        for city in cities:
            self.forecastCity(city)#循环遍历,逐一爬取和存储天气预报数据
        self.db.show()#打印数据库中数据
        self.db.closeDB()#关闭数据库

结果展示

控制台输出结果并保存数据库中,在数据库中查看

 

作业心得

1.本次作业是对书本上代码的复现,通过本次作业,我学习到了如何编写代码创建数据表并将爬取下来的数据保存到里面。

2.通过再一次分析中国天气网,再一次复习了bs库的使用,也提高了自己分析网页的能力。

3.体会到了模块化代码的便利,并尝试着使用,争取在后续的作业实践中多采用这种方式编写。

作业二

  要求:用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......                    

 

作业过程

分析网页

通过查看源代码,发现页面上的数据并不是table格式,在源代码中搜索想要的数据并不能直接找到。那该如何解决呢?

本次作业中,学习到另一种新的方法——抓包分析的方式进行爬取,用谷歌浏览器打开网址,进行抓包:

找到含有数据的js包并打开,可以看见所需爬取的数据:

获取到这个网页的url,可以看见是这样的数据形式,使用正则表达式进行解析爬取或许会更加方便。

代码部分

定义类创建数据表:

class SharesDB:
    def openDB(self):#创建表并定义表
        self.con=sqlite3.connect("shares.db")
        self.cursor=self.con.cursor()
        try:
            self.cursor.execute("create table shares (sNum varchar(16), sCode varchar(16),sName varchar(16),sNewprice varchar(16),sUpdownPercent varchar(16), sUpdownqouta varchar(16),sTurnover varchar(16),sBusinessVal varchar(16),sAmplitude varchar(16),sMax varchar(16),sMin varchar(16),sToday varchar(16),sYesterday varchar(16))")
        except:
            self.cursor.execute("delete from shares")

    def closeDB(self):#关闭数据库
        self.con.commit()
        self.con.close()

    def insert(self, Num, Code, Name, Newprice, UpdownPercent, Updownqouta, Turnover, BusinessVal, Amplitude, Max, Min, Today, Yesterday):#插入数据
        try:
            self.cursor.execute("insert into shares (sNum, sCode, sName, sNewprice, sUpdownPercent, sUpdownqouta, sTurnover, sBusinessVal, sAmplitude, sMax, sMin, sToday, sYesterday) values (?,?,?,?,?,?,?,?,?,?,?,?,?)", (Num, Code, Name, Newprice, UpdownPercent, Updownqouta, Turnover, BusinessVal, Amplitude, Max, Min, Today, Yesterday))
        except Exception as err:
            print(err)

    def show(self):#定义输出形式
        self.cursor.execute("select * from shares")
        rows = self.cursor.fetchall()
        print("%-16s%-16s%-16s%-16s%-16s%-16s%-16s%-16s%-16s%-16s%-16s%-16s%-16s" % ("序号", "股票代码", "股票名称", "最新报价", "涨跌幅", "涨跌额", "成交量", "成交额", "振幅", "最高", "最低", "今开", "昨收"))
        # print("%-16s%-16s%-16s%-32s%-16s%-16s%-16s%-16s%-32s%-16s%-16s%-16s%-16s%-32s%-16s" % ("num","city", "date", "weather", "temp"))#表头
        # for row in rows:
        #     print("%-16s%-16s%-16s%-32s%-16s" % (row[0],row[1],row[2],row[3],row[4]))
        for row in rows:
            print("%-16s%-16s%-16s%-16s%-16s%-16s%-16s%-16s%-16s%-16s%-16s%-16s%-16s" % (row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10],row[11],row[12]))

定义类获取html并爬取数据:

class Shares:
    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"}

    def sharesmarket(self):
        global num
        url = "http://19.push2.eastmoney.com/api/qt/clist/get?cb=jQuery11240009917002240502182_1634088844934&pn=1&pz=20&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&fid=f3&fs=m:1+t:2,m:1+t:23&fields=f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f12,f13,f14,f15,f16,f17,f18,f20,f21,f23,f24,f25,f22,f11,f62,f128,f136,f115,f152&_=1634088845178"
        try:
            r = requests.get(url, headers= self.headers)
            r.raise_for_status()
            r.encoding = r.apparent_encoding
            data = r.text

            sharesstring = re.findall(r"\"diff\":\[(.*?)\]", data, re.M | re.S)#正则提取字符串
            shareses = list(eval(sharesstring[0]))#将字符串转化成列表

            for shares in shareses: 
                sNum1 = num
                sCode1 = shares["f12"]
                sName1 = shares["f14"]
                sNewprice1 = shares["f2"]
                sUpdownPercent1 = shares["f3"]
                sUpdownqouta1 = shares["f4"]
                sTurnover1 = shares["f5"]
                sBusinessVal1 = shares["f6"]
                sAmplitude1 =shares["f7"]
                sMax1 = shares["f15"]
                sMin1 = shares["f16"]
                sToday1 = shares["f17"]
                sYesterday1 = shares["f18"]
                self.db.insert( sNum1, sCode1, sName1, sNewprice1, sUpdownPercent1, sUpdownqouta1, sTurnover1, sBusinessVal1, sAmplitude1, sMax1, sMin1, sToday1, sYesterday1)
                num = num + 1
        except Exception as err:
            print(err)

    def process(self):
        self.db = SharesDB()  # 创建数据库对象,db
        self.db.openDB()  # 打开数据库
        self.sharesmarket()#保存数据到数据库中
        self.db.show()#打印数据库中数据
        self.db.closeDB()#关闭数据库

结果展示

控制台输出并查看数据:

作业心得

1.本次题目,我学到了一种新的爬取方式爬取数据,对于这种抓包爬取的方式,需要更多的练习。

2.有了上一题的经验,这次的代码使用了模块化代码,大大加快了代码编写的速度。

作业三

  要求: 爬取中国大学2021主榜 https://www.shanghairanking.cn/rankings/bcur/2021
所有院校信息,并存储在数据库中,同时将浏览器F12调试分析的过程录制Gif加入至博客中。

  技巧: 分析该网站的发包情况,分析获取数据的api

  输出信息:

排名学校总分
1 清华大学 969.2

作业过程

分析网页

过程gif图:

打开url后,发现数据是乱码的,如下图:

 不过,问题应该不大,用re库解码打开,再进行分析:

 这样就可以清楚的看到学校名称和分数.,使用re正则提取相关信息。

代码部分

定义类创建数据库:

class SchoolRankDB:
    def openDB(self):#创建表并定义表
        self.con = sqlite3.connect("schoolrank.db")
        self.cursor = self.con.cursor()
        try:
            self.cursor.execute("create table schoolrank (sRank varchar(8),sName varchar(40),sScore varchar(16))")
        except:
            self.cursor.execute("delete from schoolrank")

    def closeDB(self):#关闭
        self.con.commit()
        self.con.close()

    def insert(self,rank,name,score):#插入数据
        try:
            self.cursor.execute("insert into schoolrank (sRank,sName,sScore) values (?,?,?)",(rank,name, score))
        except Exception as err:
            print(err)

    def show(self):#定义输出形式
        self.cursor.execute("select * from schoolrank")
        rows=self.cursor.fetchall()
        print("%-16s%-40s%-16s" % ("排名","学校", "总分"))#表头
        for row in rows:
            print("%-16s%-40s%-16s" % (row[0],row[1],row[2]))

创建类获取html并进行爬取:

class SchoolRank:
    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"}

    def schoolrank(self):#爬取网页信息并保存到数据库中
        url = "https://www.shanghairanking.cn/_nuxt/static/1632381606/rankings/bcur/2021/payload.js"
        try:
            r = requests.get(url, headers= self.headers)
            r.raise_for_status()
            r.encoding = r.apparent_encoding
            data = r.text

            names = re.findall(r'univNameCn:"(.*?)"', data, re.S)#采用正则直接匹配学校名称和分数,返回列表
            scores = re.findall(r'score:(.*?),', data, re.S)

            for i in range(len(names)):
                rank = i+1
                name = names[i]
                score = scores[i]
                self.db.insert( rank, name, score)
                i = i + 1

        except Exception as err:
            print(err)

    def process(self):
        self.db = SchoolRankDB()  # 创建天气数据库对象,db
        self.db.openDB()  # 打开数据库
        self.schoolrank()#将数据插入数据库
        self.db.show()#打印数据库中数据
        self.db.closeDB()#关闭数据库

结果展示

控制台输出并查看数据表:

 

作业心得

1.通过本次作业,发现自己还需要多多学习网页爬取的相关内容,css语法,js抓包操作等等操作运用的还不够熟练。

2.对于如何正确编写正则表达式,还需要更多的练习。

 

代码地址:https://gitee.com/linyu17/crawl_project/tree/master/%E7%AC%AC%E4%BA%8C%E6%AC%A1%E4%BD%9C%E4%B8%9A

posted @ 2021-10-14 21:57  今晚一定12点前睡觉  阅读(12)  评论(0编辑  收藏  举报