数据采集与融合技术_实践2

任务①:

要求:在中国气象网(http://www.weather.com.cn)给定城市集的7日天气预报,并保存在数据库。

序号 地区 日期 天气信息 温度
1 北京 7日(今天) 晴间多云,北部山区有阵雨或雷阵雨转晴转多云 31℃/17℃

1.1 实验步骤

1.1.1 确定url

  • 点进中国气象网(http://www.weather.com.cn)的链接,选择一个城市,例如北京,查看七日天气预报。

  • 通过查看网址栏,可以发现url的格式是 ./(某个地区的代号).shtml,如下图北京的代号为101010100。

  • 在确定其他地区的代号后,我们可以获得url集

self.cityCode = {"北京": "101010100", "上海": "101020100", "广州": "101280101", "深圳": "101280601"}
  • 形成完整的url准备进行访问请求
url = "http://www.weather.com.cn/weather/" + self.cityCode[city] + ".shtml"

1.1.2 urllib发送请求获取html

#此处读取的数据需要使用UnicodeDammit转换编码("utf-8", "gbk")
req = urllib.request.Request(url, headers=self.headers)
data = urllib.request.urlopen(req)
data = data.read()

1.1.3 CSS获取天气信息

  • 检查html

由图可知,七天的天气信息在 ul class="t clearfix" 中的 li 中,通过如下代码爬取天气信息

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   #获取温度信息 前者是最高温,后者是最低温
        self.db.insert(city, date, weather, temp)  #将信息插入数据库
    except Exception as err:
        print(err)

1.1.4 插入数据库及数据显示

  • 插入数据库的函数
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)
  • 数据显示
    获取所有返回值
#cursor 接收返回值 fetchall()接收全部的返回结果行
rows = self.cursor.fetchall()

       数据库show()函数格式化输出

rank=1
#chr(12288)中文空格填充
for row in rows:
    print("{0:^5}\t{1:{5}^5}\t{2:{5}^5}\t{3:{5}^5}\t{4:^5}\t".
          format(rank,row[0], row[1], row[2], row[3],chr(12288)))
    rank += 1

       结果截图:

1.1.5 代码链接

https://gitee.com/yozhibo/crawl_project/blob/master/task_2/job_1

1.2 实验心得

1.2.1 收获

  • 题目给的网址只是主页的网址,然而需要的信息并不一定就在主页中,需要自己去寻找。如本题,不同地区的天气信息被放在了不同的url中,提醒了我做题时要更灵活一些。
  • 除了CSS语法的巩固外,学会了创建class对数据库进行操作。

1.2.2 问题

  • 在晚上进行爬取时会产生 list index out of range 的错误。


    检查后发现今天的最高温信息消失了,所以在select温度时会产生错误,
    但是到了第二天早上再爬取时就会恢复正常。

任务②:

2.1 实验步骤

2.1.1 获取url

  • 观察JS包
    进入调试模式进行抓包,选择JS,为了方便查找,先将捕获的包全部清除。
  • 可以发现股票的相关信息存储在diff中
    并且f与股票的信息相对应,我们可以通过这个关系进行爬取。但是要注意一下有些参数的值可能是相同的,可以多查看几支股票进行判断。
  • 点击Headers,我们可以看见我们需要的url


  • 同时在下面还有一些其他的参数。

2.1.2 Re正则表达式爬取信息

  • 各个参数的Re表达式
no = re.findall('"f12":"(.*?)"', str(html))    # 股票代码
name = re.findall('"f14":"(.*?)"', str(html))  # 股票名称
new_price = re.findall('"f2":(.*?),', str(html))  # 最新报价
rate = re.findall('"f3":(.*?),', str(html))    # 涨跌幅
change = re.findall('"f4":(.*?),', str(html))  # 涨跌额
number = re.findall('"f5":(.*?),', str(html))  # 成交量
number_change = re.findall('"f6":(.*?),', str(html))  # 成交额
amp = re.findall('"f7":(.*?),', str(html))    # 振幅
max_ = re.findall('"f15":(.*?),', str(html))  # 最高
min_ = re.findall('"f16":(.*?),', str(html))  # 最低
now = re.findall('"f17":(.*?),', str(html))   # 今开
yes = re.findall('"f18":(.*?),', str(html))   # 昨收

2.1.3 插入函数及数据库的查看

  • 插入函数
#插入各列的值,no表示股票代码......
def insert(self,no,name,new_price,rate,change,number,number_change,amp,max_,min_,now,yes):
    try:
        self.cursor.execute("insert into shares (股票代码,股票名称,最新报价,涨跌幅,涨跌额,"
                                "成交量,成交额,振幅,最高,最低,今开,昨收) values (?,?,?,?,?,?,?,?,?,?,?,?)",
                                (no,name,new_price,rate,change,number,number_change,amp,max_,min_,now,yes))
    except Exception as err:
        print(err)

  • 使用Database Navigator查看数据库,股票代码为主码

2.1.4 代码链接

https://gitee.com/yozhibo/crawl_project/blob/master/task_2/job_2

2.2 实验心得

2.2.1 收获

  • 修改了第一题的数据库类,对创建、打开、关闭数据库,删除数据有了更深入的了解。查阅了sqlite3、cursor等的相关用法,还有避免因数据库已存在而报错的做法。
  • 页面上的数据不一定是table格式,在源代码上我们可能搜索不到想要的数据。此时可以采取抓包的方式,过滤出js文件并查看。
  • 学习了使用Database Navigator查看数据库,我们可以先运行代码生成数据库,再通过DB Browser连接数据库查看里面的数据。

2.2.2 问题

  • 数据库插入数据报错:绑定参数3时 可能不被支持

    经过检查,这是由于rate是一个列表,而创建数据库时定义rate是varchar(可变长字符串)

    解决方法:将rate改为 rate[i] ,这也是由于不够仔细而产生的错误。

任务③:

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

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

输出信息

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

3.1 实验步骤

3.1.1 调试分析过程

  • 查看头尾键值对,高校名,总分,排名,url

3.1.2 正则表达

rank = re.findall(r'ranking:(.*?),rankChange',html,re.S) #获取排名
name = re.findall(r'univNameCn:"(.*?)"', html, re.S)     #获取高校名
score = re.findall(r'score:(.*?),', html, re.S)          #获取总分

3.1.3 数据库设置

  • 排名的数据类型应该设为 INT 类型,实现按排名进行排序。
self.cursor.execute("create table universities (排名 INT(32),学校 varchar(16),"
             "总分 varchar(16),constraint pk_universities primary key (学校))")

3.1.4 结果展示

3.1.5 代码链接

https://gitee.com/yozhibo/crawl_project/blob/master/task_2/job_3

3.2 实验心得

3.2.1 收获

  • 对于抓包的过程更加熟练,清晰了url在哪找,html在哪找,其实都是相似的过程,不用感觉很陌生。
  • 第一次碰到这种不显示真实值,而用字母替代的,不知道为什么要这样做,还是挺麻烦的。不过以后碰到类似的情况就有了一点经验。
  • 再一次体会字符串排序和数字排序的差别。

3.2.2 问题

  • 爬取排名时,爬到的并非是数字

     查看了JS文件,发现这可能是一种键和值的对应关系,具体的对应关系被藏在了文件的头部和尾部。

     但这边只是处理排名的话,就没有太大必要再去做相关处理。

     如果有需要的话,可以用如下正则表达式进行获取

key = re.findall(r'function\((.*?)\)',html) #获取键
value = re.findall(r'"",(.*?)\)',html)      #获取值
  • 数据库的排序问题,如果按照字符串的排序,将是1,10,100......
    修改方式位于 3.1.3
posted @ 2021-10-16 13:11  游稚卜  Views(44)  Comments(0Edit  收藏  举报