2023数据采集与融合实践第二次作业

第二次作业

码云连接:https://gitee.com/crazypsz/spider/commit/566b31106cde3cd68bd87c63e851b299542e6565

作业一

实验

要求:在中国气象网(http://www.weather.com.cn)给定城市集的 7

日天气预报,并保存在数据库。

思路解析:

  • 预设需要存储的数据在数据库中的形式
序号 地区 日期 天气信息 温度
  • 创建存储数据的的专属类 weatherDB

该类包含以下主要方法:

  1. openDB(): 创建数据库,初始化数据库连接connect和游标cursor

  2. closeDB(): 关闭数据库

  3. insert(): 传入参数为5个数据,并将一行数据插入

  4. show():展示数据库的内容,输出到控制台

    class WeatherDB:
        def __init__(self):
            super()
    
        def openDB(self):
            self.con=sqlite3.connect("G:\database\weathers.db")
            self.cursor=self.con.cursor()
            try:
                self.cursor.execute("create table if not exists weathers (id varchar(16),wCity varchar(16),wDate varchar(16),wWeather varchar(64),wTemp varchar(32),constraint pk_weather primary key (id))")
            except:
                self.cursor.execute("delete from weathers")
    
        def closeDB(self):
            self.con.commit()
            self.con.close()
    
    
        def insert(self, count,city, date, weather, temp):
            try:
                self.cursor.execute("insert into weathers (id,wCity,wDate,wWeather,wTemp) values (?,?,?,?,?)",
                                    (count,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" % ("id","city", "date", "weather", "temp"))
            # print(“{0:{4}^16}{1:{4}^16}{2:{4}^32}{3:{4}^32}”.format(“city”,“date”,\
            # “weather”,“temp”,chr(12288)))
            for row in rows:
                print("%-16s%-16s%-16s%-32s%-16s" % (row[0], row[1], row[2], row[3],row[4]))
    
  • 编写一个爬取天气网站的类

    1. 初始化: 请求头,城市与城市代码之间的映射
    2. forecastcity():根据页面源码,解析页面数据
    3. process():接受需要爬取的城市参数,启动forecasticity()分别爬取每个城市的天气信息
    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"}
            self.count=0
        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']")[0].text.strip()
                        # print(city,date,weather,temp)
                        self.db.insert(self.count,city, date, weather, temp)
                        self.count=self.count+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.show()
            self.db.closeDB()  # 关闭数据库
    
  • 主程序

    ws = WeatherForecast()  # 创建天气预报类对象ws
    ws.process(["北京", "上海", "广州", "深圳"])  # 对指定的城市进行天气预报数据的爬取和存储
    print("completed")
    
  • 运行结果

    id city date weather temp
    0 北京 9日(今天) 晴 10℃
    1 北京 10日(明天) 晴 22℃/10℃
    2 北京 11日(后天) 晴转多云 23℃/10℃
    3 北京 12日(周四) 多云转小雨 21℃/12℃
    4 北京 13日(周五) 晴 22℃/10℃

​ ..................................................................................

心得

这个实验的页面的解析的难度不是很大,这次实验比较不一样的是要将数据存入数据库中,刚好可以熟悉一下数据库的操作,然后其实这个代码知识一个demo而已,如果没有做好城市和城市代码的映射,那么这个城市的的数据就爬不到了,如果感兴趣,可以做一个全国城市的映射,然后根据这个爬虫开发一个小程序

作业2

实验

要求:用 requests 和 BeautifulSoup 库方法定向爬取股票相关信息,并

存储在数据库中。

候选网站:东方财富网:https://www.eastmoney.com/

新浪股票:http://finance.sina.com.cn/stock/

思路解析

  • 打开东方财富网的网站,按F12,点击网络,刷新页面,观察服务器返回的各项数据,可以观察到需要的数据是在一个js的文件中

image

  • 根据上面文件的url, 解析这个js文件将其有效数据转化成Pythond的数据类型,可以发现每一条数据都是一个字典,但是其key值需要自己根据value, 做好其名称的映射,单页数据爬取的函数如下

    def get_one_pagesource(page_num=1):
        base_url =r'http://36.push2.eastmoney.com/api/qt/clist/get?cb=jQuery1124017913335698798893_1696658430311&pn={}&pz=20&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&wbp2u=|0|0|0|web&fid=f3&fs=m:0+t:6,m:0+t:80,m:1+t:2,m:1+t:23,m:0+t:81+s:2048&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&_=1696658430312'
        url = base_url.format(page_num)
        headers= {
        'User-Agent':
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36'
        }
        response = requests.get(url,headers=headers)
        content = response.content
        # print(content)
        temp_file= content
        temp_file= str(temp_file.decode('utf-8'))
        temp_file= temp_file.split('(',maxsplit=1)[1]
        temp_file = temp_file[:-2]
        # print(a)
        json_file = json.loads(temp_file)
        # print(json_file)
        data_list= json_file['data']['diff']
        for data in data_list:
            dic['名称'].append(data['f14'])
            dic['最新价格'].append(data['f2'])
            dic['涨跌幅'].append(str(data['f3'])+"%")
            dic['涨跌额'].append(data['f4'])
            dic['成交量'].append(data['f5']/1000.0)
            dic['成交额'].append(data['f6']/100000000.0)
            dic['振幅'].append(str(data['f7'])+"%")
            dic['最高'].append(data['f15'])
            dic['最低'].append(data['f16'])
            dic['今开'].append(data['f17'])
            dic['昨收'].append(data['f18'])
            dic['量比'].append(data['f10'])
            dic['代码'].append(data['f12'])
    
  • 多页数据爬取,上面的页面的url只有pn这个参数是在变化,因此只需要修改pn值,就可以访问其他网页, 由于属性太多了,就直接保存在本地的xlsx文件当中

    if __name__ =="__main__":
        num =3
        df = pandas.DataFrame()
        dic = {"代码":[], "名称":[],"最新价格":[], "涨跌额":[], "涨跌幅":[],"成交量":[], "成交额":[], "振幅":[], "最高":[], "最低":[],
                   "今开":[], "昨收":[], "量比":[]}
    
        for page_num in range(1,num+1):
            get_one_pagesource(page_num)
    
        for name in dic.keys():
            df[name]=dic[name]
        df.to_excel('./沪深京A股.xlsx')
        print('爬取结束')
    
  • 运行结果,生成的本地文件

image

心得体会

这题难点在于网络抓包吧,不仔细观察的话,就看不到数据的的接口,真正去做的话,应该大部分时间是在找借口,和做反爬,越到后面,页面解析的部分就是最简单的了

作业3

实验

要求:爬取中国大学 2021 主榜

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

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

思路解析

  • 进入网站打开f12 ,点击网络,刷新,抓取数据接口,可知数据在payload.js中

image

  • 观察文件中单项数据的源码
    image

  • 可以直接使用正则去匹配每项数据

    import requests
    import re
    import pandas
    url=r'https://www.shanghairanking.cn/_nuxt/static/1695811954/rankings/bcur/2021/payload.js'
    # url = r'https://www.shanghairanking.cn/_nuxt/static/1695811954/payload.js'
    headers={
        'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/'
    }
    response = requests.get(url,headers=headers)
    response.encoding='utf-8'
    content = response.text
    u_name = re.findall(r'univNameCn:"(.*?)"',content)
    u_score = re.findall(r'score:(.*?),', content)
    u_province = re.findall(r'province:(.*?),', content)
    df = pandas.DataFrame()
    df['学校']= u_name
    df['分数']=u_score
    df['省份']=u_province
    print(df)
    
  • 运行结果
    image

  • 另外一个思路,将获取的js文件之后获取使用 js2py 执行之后可以获取python 的数据类型,就不用使用正则去解析了

    import requests
    import js2py
    from io import StringIO
    from contextlib import redirect_stdout
    url = r'https://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_function =html[len('__NUXT_JSONP__("/rankings/bcur/2021", ('):-3]
    # js2py.eval_js(js_function) #这个方法会报错、
    js_code= f"console.log({js_function})"
    js= js2py.EvalJs()
    pyf = js2py.translate_js(js_code) #js 转换成 python
    f = StringIO() #io 流
    with redirect_stdout(f):
        exec(pyf) #底层实现
    s = f.getvalue()
    print(s)
    

心得

刚开做的时候很纠结用哪一种解析方法,一开始觉得直接使用 beautifulsoup的find是最快的,当我使用beautifulsoup解析出来之后,用尝试编写正则去解析,发现正则的方式更简单,其实原因还是在于自己对于正则表达式还不够熟悉吧,所以不能一下子就反应过来去使用正则的方式,然后第二种思路,其实一开始没想过要把里面的数据转换出来,经过老师的提醒而去尝试的

posted @ 2023-10-09 21:28  crazypsz  阅读(54)  评论(0)    收藏  举报
//鼠标跟随动画