数据采集与融合技术实践作业一

数据采集与融合技术实践作业一

gitee链接:https://gitee.com/wei-yuxuan6/myproject/tree/master/作业1

作业①

爬取大学排名信息实验

排名 学校名称 省市 学校类型 总分
1 清华大学 北京 综合 852.5
2......
  • 过程
    首先打开给定网址,使用F12查看页面源代码
    发现所有的学校信息都包含在tbody标签中,每一条学校信息都包含在tr标签中

    更进一步发现在每一条学校信息中,学校名称包含在class为'univname'的div下的class为'name-cn'的span标签中
    查找其他信息,包括排名、省市、学校类型和总分,发现信息在td标签中
    所以可以先找出所有的td标签,再通过访问列表索引的形式获取信息

  • 部分代码

# 定义要抓取数据的URL,目标是上海软科发布的2020年中国大学排名页面
url = "http://www.shanghairanking.cn/rankings/bcur/2020"

# 发送HTTP请求,并获取响应内容
response = requests.get(url)

# 设置响应内容的编码格式为UTF-8,确保中文字符显示正确
response.encoding = 'utf-8'

使用requests.get方法发送请求,获取响应后设置编码格式UTF-8,之后就可以使用response.text获取响应文本

# 使用BeautifulSoup解析响应的HTML内容,"lxml"为解析器类型
soup = BeautifulSoup(response.text, "lxml")

# 查找包含学校排名数据的表格主体
table = soup.find('tbody')

# 查找表格中的所有行(即每所学校的排名信息)
rows = table.find_all('tr')

# 打印表格的标题行,表示排名、学校名称、省市、学校类型、总分
print("{:<5} {:<15} {:<8} {:<8} {:<6}".format("排名", "学校名称", "省市", "学校类型", "总分"))

# 遍历每一行数据,并提取出学校排名和信息
for row in rows:
    # 查找学校名称,包含在class为'univname'的div下的class为'name-cn'的span标签中
    school = row.select("div[class='univname'] span[class='name-cn']")
    # 提取学校名称,并去除前后空白字符
    school = school[0].text.strip()

    # 查找其他信息,包括排名、省市、学校类型和总分,信息在<td>标签中
    info = row.select("td")

    # 提取排名信息并去除空白字符
    rank = info[0].text.strip()

    # 提取学校所在的省市信息并去除空白字符
    province = info[2].text.strip()

    # 提取学校类型(如综合类、理工类等)并去除空白字符
    typ = info[3].text.strip()

    # 提取学校的总分信息并去除空白字符
    score = info[4].text.strip()

    # 格式化输出,每个字段设定固定宽度,方便对齐
    # 对学校名称进行宽度控制,确保对齐
    school_name = school.ljust(12, ' ')  # 使用全角空格对齐
    print("{:<5} {:<12} {:<8} {:<8} {:<6}".format(rank, school_name, province, typ, score))

这里使用了BeautifulSoup的find、find_all、CSS选择器结合的方法,查找其他信息时使用CSS选择器找出所有td标签,返回列表,排名字段在第一个td标签中,省市字段在第三个td标签中……
值得注意的是提取出来的文本都带有空白字符,所以需要使用.strip()方法进一步处理
刚开始尝试了几次输出发现输出内容不整齐,主要是学校与省市之间因为学校字段长度不同,是因为中文后面使用半角空格填充,所以学校字段长度不同填充后的长度也不同,所以使用全角空格将学校字段填充到12个字符

心得体会

复习了使用BeautifulSoup的find、find_all、CSS选择器查找HTML文档元素,还学会了如何对结果格式化输出(使用format和对中文的全角空格填充),主要是要查找HTML文档中各个元素的规律,定位到需要元素所在位置

作业②

商品比价定向爬虫实验

  • 要求:用requests和re库方法设计某个商城(自已选择)商品比价定向爬虫,爬取该商城,以关键词“书包”搜索页面的数据,爬取商品名称和价格。
  • 输出信息:
序号 价格 商品名
1 65.00 xxx
2......
  • 过程
    这里爬取的是京东的商品数据
    首先打开京东搜索“书包”,查看源代码并分析
    发现每个商品都包含在li元素中,价格在class为"p-price"的div元素中,名字在class为"p-name p-name-type-2"的div下的em元素中

    同时想要访问京东必须在请求中添加请求头(包括User-Agent和Cookie)
    在Network中找到Search?开头的,点击Headers就可以找到对应的参数

  • 部分代码

while (1):  # 开始循环抓取网页数据,直到获取到指定数量的商品

    # 构造URL,包含查询的商品名称和页数,使用 urllib.parse.quote 进行 URL 编码
    url = "https://search.jd.com/Search?keyword=" + urllib.parse.quote(q) + \
          "&qrst=1&wq=" + urllib.parse.quote(q) + "&stock=1&pvid=5977ce2bd05f4ea5ad2f9f78c0b1787b&isList=0&page=" \
          + str(i) + "&s=56&click=0&log_id=1729158516273.3620"

    response = requests.get(url, headers=headers)  # 发送请求,获取响应内容
    response.encoding = 'utf-8'  # 设置响应内容的编码格式为UTF-8,确保中文显示正常

首先构造URL,并使用requests.get发送请求,这里还使用了 urllib.parse.quote 进行 URL 编码,可以爬取不同商品(但是不同页面源代码不同,不一定能爬取到),还进行了翻页处理,每一页只有30个商品,想要爬取更多就需要翻页,通过查找URL的规律,页数在page=中体现

# 匹配价格信息,价格信息包含在 <i> 标签中
    reg1 = r"<i data-price=[^>]*>.*?</i>"
    # 匹配价格的具体数值,格式为“数字.数字”,如 "123.45"
    reg2 = r"[0-9]+[.]+[0-9]+"
    # 匹配商品名称信息,商品名称包含在 <div class="p-name p-name-type-2"> 标签中
    reg3 = r"<div class=\"p-name p-name-type-2\">.*?</div>"
    # 在每个商品名称信息中匹配商品名称,商品名称包含在 <em> 标签中,但不能以“¥”开头
    reg4 = r"<em>[^¥].*?</em>"
    # 匹配HTML标签,用于去除商品名称中的HTML标签
    reg5 = r"<[^>]*>"

    # 使用 re.findall 查找所有价格标签
    pricetags = re.findall(reg1, response.text, re.S)
    for pricetag in pricetags:
        # 从每个价格标签中提取出价格数值
        pricel = re.findall(reg2, pricetag)
        price = pricel[0]  # 获取第一个匹配的价格
        pricelist.append(price)  # 将价格添加到价格列表中

    # 使用 re.findall 查找所有商品名称标签
    nametags = re.findall(reg3, response.text, re.S)
    for nametag in nametags:
        # 去除HTML标签中的空格,避免空格影响后续处理
        nametag = re.sub(r"\s+", '', nametag)
        # 从商品名称中提取出实际的名称,并去除HTML标签
        names = re.findall(reg4, nametag)
        name = re.sub(reg5, '', names[0])  # 去除 HTML 标签,获取商品名称
        namelist.append(name)  # 将商品名称添加到名称列表中

        # 如果已经获取到用户指定数量的商品,就跳出循环
        if count == int(num):
            break
        count += 1  # 计数器加1,表示已经处理了一个商品

    i += 1  # 页面计数器加1,开始抓取下一页
    if i > page:  # 如果已经抓取到用户指定的页面数量,就跳出循环
        break
    time.sleep(1)  # 暂停1秒,防止请求过于频繁,避免被服务器封禁

这里使用了正则表达式查找需要的元素
刚开始想要使用通过匹配li元素获得每个商品的信息,但是发现在每个商品中也有li元素,导致匹配错误,所以选择直接匹配价格信息,价格信息包含在i标签中有属性data-price,还要在找到的标签中匹配价格的具体数值,因为findall方法返回的是列表,所以可以直接通过索引使用如pricel[0](只有一个)
后面还直接匹配了商品名称信息,但是发现在商品名称信息中还有HTML标签以及尝试提取出的信息和有的标签之间有空格,所以使用了re.sub方法,找到所有HTML标签和空格都替换成空字符
比如以下标签

同时还记录了商品的个数,及页数便于翻页处理
因为不能直接输出结果(查找价格和名称在两个不同循环中),所以定义了两个列表分别存储价格和商品名称,最后格式化输出

心得体会

本次实验主要复习了正则表达式的使用,学会了使用正则表达式查找指定字符并替换,还有翻页处理,通过找到不同页URL的规律改变URL参数进行翻页。但是感觉自己对正则表达式的使用不太熟练,需要修改多次、进行多次调试才写出正确的正则表达式(所以将爬取到的HTML文件保存到本地,测试通过之后再访问网站),还需要进一步练习。

作业③

爬取网页图片实验

  • 要求:爬取一个给定网页( https://news.fzu.edu.cn/yxfd.htm) 或者自选网页的所有JPEG和JPG格式文件

  • 输出信息:将自选网页内的所有JPEG和JPG文件保存在一个文件夹中

  • 过程
    打开网页,分析页面源代码,该页面结构清晰
    每个新闻在li元素中,图片连接在li下class='img slow'的div元素下的img的src属性中
    所以选择使用BeautifulSoup的CSS选择器比较方便
    但是在访问的时候要在获得的链接前加上"https://news.fzu.edu.cn"

  • 部分代码

# 设置要爬取的网页地址
url = "https://news.fzu.edu.cn/yxfd.htm"

# 创建请求对象,用于向目标网页发送请求
req = urllib.request.Request(url)

# 打开URL并获取响应
response = urllib.request.urlopen(req)

# 读取响应内容并将其解码为 UTF-8 编码格式的文本
html = response.read().decode('utf-8')

# 使用BeautifulSoup解析网页内容,解析器使用'lxml'
soup = BeautifulSoup(html, "lxml")

这里使用了urllib.request发送请求,因为urllib.request提供了urllib.request.urlretrieve方法,后续可以直接将访问到的图片保存到本地

# 选择所有匹配的图像元素,图像元素包含在 <li> 标签下,class 属性为 'img slow'
items = soup.select("li div[class='img slow'] img")

# 初始化计数器,记录下载的图片数量
count = 1

filedir="D:/数据采集/实验/1/picture2/"
os.makedirs(filedir, exist_ok=True)

# 循环遍历匹配到的所有图像元素
for item in items:
    # 检查图片的src属性是否以 .jpg 或 .jpeg 结尾,判断是否为目标图片格式
    if item['src'].endswith(".jpg") or item['src'].endswith(".jpeg"):
        # 拼接完整的图片URL,"https://news.fzu.edu.cn" 是图片的基础地址
        image_url = "https://news.fzu.edu.cn" + item['src']

        # 下载图片,并保存到指定的文件夹,文件名使用当前计数器的值
        urllib.request.urlretrieve(image_url, filedir + str(count) + ".jpg")

        # 打印下载进度信息,包含图片编号和图片URL
        print("正在下载第" + str(count) + "张图片, 地址为:" + image_url)

        # 下载完成后计数器加1
        count += 1

这里使用os.mkdirs创建文件夹
然后是匹配过程,还有因为题目要求爬取所有的jpg和jpeg文件,所以对获得的图片连接进行检查是否以.jpg和.jpeg结尾
然后拼接完整的图片URL并访问

心得体会

本实验复习了在访问初始URL时获取新的URL并访问的过程,就是再次对新的URL发出请求的过程,同样使用urllib.request,与请求初始URL时相同,后续如果爬取的图片较多的话可以使用多线程提高爬取速度。

posted @ 2024-10-18 19:17  Mysterious-x  阅读(24)  评论(0编辑  收藏  举报