数据采集第一次作业(2022)
作业1:
题目:要求用urllib和re库方法定向爬取给定网址2020中国最好学科排名的数据。输出信息如下:
2020排名 | 全部层次 | 学校类型 | 总分 |
1 | 前2% | 中国人民大学 | 1069.0 |
2 | ... | ... | ... |
解题:
url="https://www.shanghairanking.cn/rankings/bcsr/2020/0812" headers={"User-Agent":"Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9pre) Gecko/2008072421 Minefield/3.0.2pre"} req=urllib.request.Request(url,headers=headers) data=urllib.request.urlopen(req)# 发送请求 soup=data.read().decode('utf-8')# 解析网页
1.2根据网页结点信息构造正则表达式
rank=[] level=[] school=[] score=[] for items in re.findall(r'<tr data-v-68e330ae>.*?</tr>', soup, re.S|re.M): for a in re.findall(r'<div class="ranking".*?>(.*?)</div>',items,re.S|re.M): rank.append(int(a)) #记录排名 for b in re.findall(r'<td data-v-68e330ae.*?>(.*?)</td>',items,re.S|re.M): for k in re.findall(r'(.*?)<!---->',b,re.S): level.append(k.strip()) #记录层次 for k in re.findall(r'\d+\.\d',b,re.S): score.append(k.strip()) #记录总分 for c in re.findall(r'<a .*?name-cn.*?>(.*?)</a>', items, re.S|re.M): school.append(c)# 记录学校
1.3输出代码
tplt = "{0:^10}\t{1:{4}<10}\t{2:<10}\t{3:<10}" print(tplt.format("2020排名", "全部层次", "学校名称", "总分", chr(12288))) for i in range(len(rank)): print(tplt.format(rank[i],level[i],school[i],score[i],chr(12288))) #中英文混排时采用chr(12288)
1.4输出结果
作业2:
要求:用requests和Beautiful Soup库方法设计爬取https://datacenter.mee.gov.cn/aqiweb2/ AQI实时报。
输出信息:
序号 | 城市 | AQI | PM2.5 | .. | .. | .. | .. |
1 | 北京 | ... | ... | ||||
解题
获取http
使用requests进行Get请求:
url = "https://datacenter.mee.gov.cn/aqiweb2/" response = requests.get(url) html = response.text # 使用缓存,防止被ban # with open('./.cache/aqiweb2.html', 'r', encoding='utf-8') as f: # html = f.read()
同上,添加一个缓存。
构建soup,解析表格
这里需要先解析下图中选中部分的表格:
使用Beatiful Soup进行解析:
# 构建soup对象 soup = BeautifulSoup(html, "lxml") # 解析表格 table = soup.find('div', attrs={"id": "demo"}).table.tbody
提取数据
查看该表格,发现该tbody内,tr均匀排列,且各个tr内的td内容即为需要的数据(即td.text):
因此,只需要进行两层遍历,就能提取出所有信息:
i = 0 for tr in table.find_all('tr'): print("{:^6}".format(i), end='\t') for td in tr.find_all('td'): print("{:^6}".format(strQ2B(clear_data(td.text))), end='\t') print() i += 1
2、运行结果
3、文件地址:https://gitee.com/mirrolied/spider_test/blob/master/lesson_2/session_2.py
作业3
要求:使用urllib和requests爬取(https://news.fzu.edu.cn/),并爬取该网站下的所有图片输出信息:将网页内的所有图片文件保存在一个文件夹中
解题
获取html
由于该题要求使用urllib.request和requests进行爬取,索性将两种方法结合缓存(即读取本地文件)整合成一个函数,由用户选择请求方法。
构建一个get_html函数,输入url以及请求方法,返回html文本:
def get_html(url: str, request_type: str) -> str: """ 获取html :param url: 访问地址 :param request_type: 请求方式: urllib.request 或 urllib.request 或相应缓存 :return: html """ if request_type == "urllib.request": # urllib.request return urllib.request.urlopen(url).read().decode("utf-8") elif request_type == "requests": # requests response = requests.get(url) return response.text else: # 读取缓存文件 with open(f'./.cache/{request_type}.html', 'r', encoding='utf-8') as f: return f.read()
解析图片
使用正则匹配的方式,将所有的<img>标签内的src提取出来:
imgList = re.findall(r'<img.*?src="(.*?)"', html, re.S)
图片保存
文件内容即请求图片url返回内容,使用with open创建文件管理对象,并将模式设置为wb(二进制写入模式):
resp = requests.get(img_url) with open(f'./download/{img.split("/")[-1]}', 'wb') as f: f.write(resp.content)
使用字符串分割从url中提取出文件的名称(保证后缀名无误):
img.split("/")[-1]
或以"."进行分割,仅提取后缀名,自己对文件进行标号命名。
最后使用f.write(resp.content)即可实现保存。
def get_imgs(html:str, download=True) -> None: """ 获取所有图片地址,可选择下载 :param html: 输入html :param download: 是否下载 :return: None """ imgList = re.findall(r'<img.*?src="(.*?)"', html, re.S) print(imgList) print(f'共有{len(imgList)}张图片') if download: for i, img in enumerate(imgList): img_url = "http://news.fzu.edu.cn" + img print(f"正在保存第{i + 1}张图片 路径:{img_url}") resp = requests.get(img_url) with open(f'./download/{img.split("/")[-1]}', 'wb') as f: f.write(resp.content) 复制代码
运行结果
本次作业gitee地址:https://gitee.com/mirrolied/spider_test/tree/master/lesson_1