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


作业①


1) 解题思路

1.1 获取网页的HTML

​ 采用urllib的方式爬取网页

#获取网页内容
def getHTMLTextUrllib(url):
    try:
     	#请求头进行伪装
        headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 '
            '(KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 SLBrowser/7.0.0.6241 SLBChan/30'}
      		
        req = urllib.request.Request(url,headers=headers)
        resp = urllib.request.urlopen(req)
        data = resp.read()
        data = data.decode()
        #print(data) 返回爬取到的HTML数据
        return data

    except Exception as err:
        return err

​ ✨ 针对urllib.request.

  1. 如果要加入headers等信息,需要先用Request类构造请求req。

  2. 使用request.urlopen(req)打开url网址。

  3. read()函数读出网站的二进制内容,再用decode()函数解码(默认utf-8)

  4. 不能直接解析带中文的网址,要使用urllib.parse.quote进行转化

1.2 正则表达式

​ 检查网页HTML,将tbody的内容输出并复制到文本文件中,方便查找所需对应位置。


经过调试,最终得到下表reg:

代码:

    try:
        #经测验,空格可以用.匹配到
        #用""替换换行符,因为.无法匹配换行符
        data=re.sub(r"\n","",str(data))
        #print(data)
        rank2020=re.findall(reg_rank2020,data)
        level=re.findall(reg_level,data)
        name=re.findall(reg_name,data)
        score=re.findall(reg_score,data)
    except Exception as err:
        print(err)

​ ✨学习和巩固Re知识

  1. ()可以选择要输出的部分!

  2. 首次使用re.sub(),{}等,前者替换字符子串,返回替换后的字符串,后者代表重复次数。

1.3 结果输出

#代码部分
def printSelected_Data():
    #头部是各列列名,和值分开输出,便于控制对齐
    head = ["2020排名", "全部层次", "学校名称", "总分"]
    print("{0:^10}\t{1:^10}\t{2:^6}\t{3:^12}\t".format
          (head[0], head[1], head[2], head[3]))
    # 输出爬取数据,前两列居中,后两列靠右对齐,使输出较为整齐
    for i in range(len(rank2020)):
        print("{0:^10}\t{1:^10}\t{2:>10}\t{3:>10}\t".format
              (rank2020[i], level[i], name[i], score[i]))

​ 输出结果展示:

1.4 代码地址

https://gitee.com/yozhibo/crawl_project/blob/master/task_1/job_1.py

2) 心得体会

​ 任务一,主要是对urllib和re库方法两者的使用进一步熟悉,在做的过程中出现了一些问题,在解决问题时我对于Re的使用更加熟练,值得花时间学习巩固,下面是我对于如何正则匹配的一些心得。

​ 在正则匹配调试时一定不能只看检查网页的HTML,因为我们可能还会对爬取到的HTML做修改,在网页中看到的跟爬取下来的有些地方会不一样。把data输出复制到txt文本中,不容易出错。另一方面也可以先匹配更多的内容,如r'td data-v-68e330ae>.* ,这样我们就可以比较容易看见r'td data-v-68e330ae>后面的内容是怎样的,也就能对症下药。


作业②

  • 要求:用requests和Beautiful Soup库方法设计爬取https://datacenter.mee.gov.cn/aqiweb2/ AQI实时报。
  • 输出信息:
序号 城市 AQI PM2.5 SO2 No2 Co 首要污染物
1 北京 55 6 5 1.0 225
2......

1) 解题思路

1.1 获取网页的HTML

​ 采用Requests的方式爬取网页

#获取HTML
def getHTMLTextRequest(url):
    try:
        #请求头
        headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 '
                '(KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 SLBrowser/7.0.0.6241 SLBChan/30'}
        res = requests.get(url,headers=headers)
        #转化编码方式,注意不要直接转成uft-8类型,不一定是对的
        res.encoding=res.apparent_encoding
        #print(res.text)
        return res.text

    except Exception as err:
        return err

​ ✨ 针对Requests.

  1. requests可以直接构造get,post等请求并发起,会更加便捷。

  2. 直接text输出的话,返回unicode 型的数据,中文无法显示。

  3. res.encoding=res.apparent_encoding修改编码方式,本题中utf-8不能显示中文。

  4. 可以解析带中文的网址。

1.2 BeautifulSoup

​ 检查网页HTML,所需内容依然在tbody中,通过soup.find("tbody").children可以获得tr列表,再对每个tr进行find_all('td')操作,获取相应的文本。

代码:

#使用find查找所需数据
def fillUnivList_Find(data):
    soup = BeautifulSoup(data,"lxml")
    #或者用 for tr in soup.find('tbody').children:
    trs = soup.find("tbody").children
    #print(trs)
    for tr in trs:
        #判定tr是否属于bs4库中tag类型
        if isinstance(tr, bs4.element.Tag):
            tds=tr.find_all('td')
            #append td中所需文本 strip去除空格
            name.append(tds[0].text.strip())
            AQI.append(tds[1].text.strip())
            PM.append(tds[2].text.strip())
            SO2.append(tds[4].text.strip())
            NO2.append(tds[5].text.strip())
            Co.append(tds[6].text.strip())
            prim.append(tds[8].text.strip())

✨关于isinstace(tr, bs4.element.Tag)

  1. 在这里如果不对tr进行判断,会产生如上图的错误,查询资料发现需要过滤掉bs4库不支持的Tag类型。

1.3 结果输出

#代码部分
def printSelected_Data():
    head = ["序号", "城市", "AQI", "PM2.5", "SO2","NO2","Co","首要污染物"]
    print("{0:^10}\t{1:^10}\t{2:^15}\t{3:^10}\t{4:^10}\t{5:^10}\t{6:^10}\t{7:^10}\t".format
          (head[0], head[1], head[2], head[3], head[4],head[5],head[6],head[7]))
    # 输出爬取数据
    for i in range(200):
        rank.append(i+1)
        print("{0:^10}\t{1:^10}\t{2:^10}\t{3:^10}\t{4:^10}\t{5:^10}\t{6:^10}\t{7:^10}\t".format
              (rank[i], name[i], AQI[i], PM[i], SO2[i],NO2[i],Co[i],prim[i]))

format格式化输出,使输出较为整齐。

✨疑惑

​ 有时候print(res.apparent_encoding) 时结果为None,在进行编码转化时会导致中文无法正确表示。

结果:

解决方式:直接转化 res.encoding='GB18030' ,但是不同电脑解析出来编码方式的似乎不一定相同。

1.4 代码地址

https://gitee.com/yozhibo/crawl_project/blob/master/task_1/job_2.py

2) 心得体会

​ 本题主要是对Requests和BeautifulSoup的再复习,与之前的练习很相似,只是输出的内容更多了。这边还是采用将爬取到的信息,按每一列分别存储到数组的方式进行,最终输出。

​ 值得注意的有两点,一是关于转化编码方式 ,因为res.encoding=res.apparent_encoding要先去判断网页的编码方式,可能比较耗费时间和资源,我就直接把编码方式直接转化为utf-8,一开始没多想,结果无法输出中文,后来发现这是由于编码不一致造成的。经输出可以发现编码为gb18030,不是我想当然的utf-8,这是第一个要注意的点。二是输出的整齐性,虽然这次我没有使用chr(12288)进行填充,但我对于chr(12288)的使用有了进一步的了解。一开始我以为{5}是填充5格的意思,后来才发现是表示填充方式为索引为5的内容,即用处于第六位的chr(12288)进行填充。


作业③

  • 要求:使用urllib和requests爬取(http://news.fzu.edu.cn/),并爬取该网站下的所有图片

  • 输出信息:将网页内的所有图片文件保存在一个文件夹中

  • 输出信息:

序号 城市 AQI PM2.5 SO2 No2 Co 首要污染物
1 北京 55 6 5 1.0 225
2......

1) 解题思路

1.1 获取网页的HTML

​ 采用urllib/requests的方式爬取网页,在主函数中实现让用户进行选择,以urllib或requests进行爬取。

#获取网页内容
def Get_HTMLTextRequest(url):
    try:
        #请求头
        headers ={
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 '
                '(KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 SLBrowser/7.0.0.6241 SLBChan/30' ,
        }
        #获取response
        res = requests.get(url,headers=headers)
        res.encoding=res.apparent_encoding
        #print(res.text)
        return res.text
    except Exception as err:
        return err

def getHTMLTextUrllib(url):
    try:
        headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 '
            '(KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 SLBrowser/7.0.0.6241 SLBChan/30'
        }
        req = urllib.request.Request(url,headers=headers)
        resp = urllib.request.urlopen(req)
        data = resp.read()
        #decode解码
        data = data.decode()
        #print(data)
        return data

    except Exception as err:
        return err

​ ✨ 针对urllib和requests

​ 目的都是实现对网站的请求,获取网站中的内容。

1.2 Re正则匹配

​ 为了减少服务器的负担,以及避免被封,将html输出复制到文本文件中,确认reg后再重新爬取。

​ 图片的链接格式如下图可见:

最终可以确定reg为:

    reg_img=r'img src=\"(.*?)\"'

​ 由于爬取到的网址只是相对地址,所以还需要加上绝对地址:

    for i in range(len(list_img)):
        url = list_img[i]
        #print(url)
        #如果url开头不是http,则补充http://,同时补充为绝对地址
        if url[0:4]!="http":
            url="http://news.fzu.edu.cn/"+url
        imgurl.append(url)

1.3 输出链接地址

#输出图片链接
def PrintResult(imgurl):
    head = ["序号", "图片链接"]
    print("{0:^10}\t{1:^20}\t".format
          (head[0], head[1]))
    for i in range(len(imgurl)):
        print("{0:^10}\t{1:^20}\t".format
              (i+1,imgurl[i]))

效果展示:

1.4下载图片至同一个文件夹

#保存图片路径
path='img/'
#如果路径不存在则创建
if not os.path.exists(path):
  os.mkdir(path)
#图片的路径,保留图片格式 jpg/png/gif
path_img = path+str(i+1)+imgurl[i][-4:]

结果展示:

1.5 主函数

#主函数
if __name__=='__main__':
    imgurl = []
    url="http://news.fzu.edu.cn/"
    #用户选择
    while True:
        method=input("请选择urllib或requests进行爬取:")
        if method=="urllib":
            data=getHTMLTextUrllib(url)
            break
        elif method=="requests":
            data=Get_HTMLTextRequest(url)
            break
        else:
            print("Wrong")
            continue
    #print(data)
    img=getImgURL(data,imgurl)
    PrintResult(img)
    Downloads(img)

效果展示:

1.6 代码地址

https://gitee.com/yozhibo/crawl_project/blob/master/task_1/job_3.py

2) 心得体会

​ 我认为本题主要是重新再巩固一下urllib和requests两种方式爬取网页,对比他们的不同,提取相同点,以及Re库的巩固。做题时,我再一次踩入了相对网址的坑,一直无法完整显示链接,直到后来才意识到爬取到的只是相对网址,以后多多注意。

​ 另一方面,在爬取的过程中,我一开始觉得福大新闻网可能是把我的IP给封了,拒绝我的连接,后更换网络后爬取成功。这警示着我一定要先把爬取到内容保存起来,可以先爬文件,等一切就绪后再爬取网页。再后来使用新网络也无法连接,最终发现该网站链接应该使用http而不是https。

posted @ 2021-10-02 07:53  游稚卜  Views(93)  Comments(0Edit  收藏  举报