数据采集技术第一次作业

作业

No.1——UniversitiesRanking

题目要求

用requests和BeautifulSoup库爬取网址(http://www.shanghairanking.cn/rankings/bcur/2020)的数据,屏幕打印爬取的大学排名信息。

代码部分

import bs4
import urllib.request
Url = 'http://www.shanghairanking.cn/rankings/bcur/2020'
#获取指定网站的html并编码
req=urllib.request.urlopen(Url)
data=req.read()
html=data.decode()
#装载html
s=bs4.BeautifulSoup(html,'html.parser')
#定位到大学的名字
tags=s.select("a[href$='university']")#匹配href以university为结尾的a节点
print("排名	学校名称	省市	类型	总分")
for i in tags:
    name=i.parent
    print(i)
    ranking=name.previous_sibling #寻找前一个兄弟结点
    city=name.next_sibling #寻找下一个兄弟节点
    typing=city.next_sibling
    score=typing.next_sibling
    print(ranking.text.strip()+'	'+i.text.strip()+'	'+city.text.strip()+'	'+typing.text.strip()+'	'+score.text.strip())

最终部分结果如下图

心得体会

解题过程

1.格式提取

获取html以后观察其中一个大学的html格式如图

Url = 'http://www.shanghairanking.cn/rankings/bcur/2020'
tar=urllib.request.urlopen(Url)
html=tar.read().decode()
发现大学名字前面总是有大学的英文拼写,且都以university结尾,想到可以用[attName$=value]来匹配attName属性以value结尾的结点来定位学校名称,并调用select方法查找符合表达式的结点。

2.获取兄弟节点

利用previous_sibling()和next_sibling()获取前后兄弟结点,也就是学校的排名、省市、类型、总分等结点,但是在测试的时候出现了错误,测试代码如下

tags=s.select("a[href$='university']")
for i in tags:
    ranking=i.previous_sibling
    print(ranking)

但是却输出了

于是查看了tags(也就是上面select出来的html)

预期中想定位到前面排名的值的结点,然而这与上上图的i并不是兄弟关系,而与i的父节点是兄弟关系

于是修改了测试代码

tags=s.select("a[href$='university']")
for i in tags:
    ranking=i.parent.previous_sibling
    print(ranking)

成功获取到了排名所在的结点

之后的排名等属性值也按照这样获取即可

3.输出结果

对ranking调用text方法获取结点的文本内容,但是问题又出现了

获取文本内容以后保留了原本的格式,影响输出,查询资料以后使用strip()方法可以清除格式

  • 初见,看书问同学查资料,才能勉强维持生活
  • No.2——GoodsPrice

    题目要求

    用requests和re库方法设计某个商城(自已选择)商品比价定向爬虫,爬取该商城,以关键词“书包”搜索页面的数据,爬取商品名称和价格。

    代码部分

    import requests
    import re
    from bs4 import BeautifulSoup
    headers = {"User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9pre) Gecko/2008072421 Minefield/3.0.2pre"}
    keyword = "键盘"
    #获取html文件
    url = 'https://search.jd.com/Search?keyword='+keyword
    r = requests.get(url, headers=headers)
    html = r.text
    #载入html文档
    soup = BeautifulSoup(html, 'html.parser')
    allItem=soup.select("div[class='gl-i-wrap']")
    #格式筛选与输出
    print("{:4}	{:10}".format("价格", "商品名称"))
    for i in range(30):
    	productPrice = allItem[i].select("div[class='p-price'] i") #获取商品价格的结点 productPrice是一个列表
    	price=productPrice[0].text
    	producttitle = allItem[i].select("div[class='p-name p-name-type-2'] em")#获取商品名称的结点
    	title=producttitle[0].text.replace('
    ','')
    	print("{:4}	{:10}".format(price, title))
    

    最终部分结果如下图

    心得体会

    解题过程

    1.格式提取

    获取的html源代码如下图

    headers = {"User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9pre) Gecko/2008072421 Minefield/3.0.2pre"}
    keyword = "书包"
    url = 'https://search.jd.com/Search?keyword='+keyword
    r = requests.get(url, headers=headers)
    html = r.text

    找到了价格和商品名称对应的div结点,class分别为p-price和p-name p-name-type-2,而他们的父节点的class名为gl-i-wrap,所以用select方法将class名为gl-i-wrap的div结点选择出来

    soup = BeautifulSoup(html, 'html.parser')
    allItem=soup.select("div[class='gl-i-wrap']")

    2.获取子节点

    价格所在的div class=p-price结点的html如图

    根据属性语法规则,选择class属性为p-price的div结点选择器为"div[class='p-price']",然后直接定位到价格的结点i,查找子孙结点的格式为"div[class='p-price'] i",就可以直接定位到价格

    productPrice = allItem[i].select("div[class='p-price'] i")
    print(productPrice[0])

    获取商品名称也与上相似,只是匹配内容改一下而已

    3.结果输出

    还是调用text方法获取结点内的文本,在测试输出商品名称的时候,发现有些商品前缀有写明室隶属于京东超市或者京品数码等所属,在输出的时候有换行符,导致格式不正确

    于是用replace方法,将换行符替换为空

    replace('
    ','')

    之后就按形式输出表头

    print("{:4}	{:10}".format("价格", "商品名称"))
    并且输出每个输出的价格和名称
    print("{:4}	{:10}".format(price, title))

  • 二周目,姑且可以变通运用书上的方法,再加以百度的小小点缀,过程并不算痛苦
  • No.3——JPGFileDownload

    题目要求

    爬取一个给定网页(http://xcb.fzu.edu.cn/html/2019ztjy)或者自选网页的所有JPG格式文件

    代码部分

    import requests
    import bs4
    import os
    #获取html文件
    url=requests.get("http://xcb.fzu.edu.cn")
    html=url.text
    #加载html文档
    soup = bs4.BeautifulSoup(html,'html.parser')
    imgList=soup.select("img[src$='jpg']") #存储img结点
    srcList=[] #用于存储src
    #获取src的值
    for i in imgList:
        srcList.append(i.get("src"))
    for src in srcList:
        #src链接格式化
        if src[0]=='/':
            src='http://xcb.fzu.edu.cn'+src
        #写入图片
        with open("./File/"+os.path.basename(src),'wb') as f:
            f.write(requests.get(src).content)
        print(os.path.basename(src)+"下载成功")
    

    代码运行结果如下

    下载结果

    心得体会

    解题过程

    1.格式提取

    url=requests.get("http://xcb.fzu.edu.cn")
    html=url.text
    soup = bs4.BeautifulSoup(html,'html.parser')

    获取了福州大学宣传部的html,其中一部分jpg图片的格式如下图

    发现只要select img结点就可以获取所有图片的结点了

    imgList=soup.select("img")

    获取以后发现,网站内不止有jpg的图片,也有png和gif

    于是用属性匹配规则,只选取以jpg为结尾的结点

    imgList=soup.select("img[src$='jpg']")

    2.下载文件

    创建一个File文件夹,用于存储图片

    下载图片需要用到src,于是用get方法将上面imgList中吧src提取出来加入到srcList里面

    srcList=[]
    for i in imgList:
        srcList.append(i.get("src"))

    结果如下图

    使用basename方法从src获取文件的名字

    下载图片有许多方式,这里参考了https://blog.csdn.net/weixin_43715458/article/details/101283489里面的方案2

    for src in srcList:
        with open("./File/"+os.path.basename(src),'wb') as f:
            f.write(requests.get(src).content)

    但是出现了错误,无效的url

    与同学交流以后发现需要在这类src前面加上源网址才可以获取图片

    于是修改为,并添加保存成功的标识

    for src in srcList:
        if src[0]=='/':
            src='http://xcb.fzu.edu.cn'+src
        with open("./File/"+os.path.basename(src),'wb') as f:
            f.write(requests.get(src).content)
        print(os.path.basename(src)+"下载成功")

  • 能完成的情况下回头一看自己的代码属实不够美观(丑),下次争取在完成的情况下规范一下代码格式~
  • 原文地址:https://www.cnblogs.com/axx4136/p/13733188.html