Python网络爬虫与信息提取学习笔记(第0、一、二周)

Python爬虫

request库

import requests
r = requests.get("https://www.icourse163.org")
print(r.status_code)		#状态码200,访问成功

print(type(r))  #<class 'requests.models.Response'>

#编码方式
print(r.encoding)       #charset字段获得,不存在默认为ISO-8859-1
print(r.apparent_encoding)  #备选编码,通过分析内容推断出编码

r.encoding = 'utf-8'		#设置编码

print(r.text)		#html内容
print(r.headers)	#http请求头
print(r.content)        #用于解析图片等内容
request对象属性
r.status_codeHTTP请求的返回状态,200表示连接成功,404表示失败
r.textHTTP响应内容的字符串形式,即url对应的页面内容
r.encoding从HTTP header中猜测的响应内容编码方式
r.apparent_encoding从内容中分析出的响应内容编码方式(备选编码方式)
r.contentHTTP响应内容的二进制形式
request对象方法

方法说明

requests.request()构造一个请求,支撑以下各方法的基础方法
requests.get()获取HTML网页的主要方法,对应于HTTP的GET
requests.head()获取HTML网页头信息的方法,对应于HTTP的HEAD
requests.post()向HTML网页提交POST请求的方法,对应于HTTP的POST
requests.put()向HTML网页提交PUT请求的方法,对应于HTTP的PUT
requests.patch()向HTML网页提交局部修改请求,对应于HTTP的PATCH
requests.delete()向HTML页面提交删除请求,对应于HTTP的DELETE
通用代码框架
import requests  
import time
def getHTMLText(url):
    """
    获取指定 URL 的 HTML 内容

    Parameters:
        url (str): 要获取 HTML 内容的 URL

    Returns:
        str: 成功获取到的 HTML 内容,如果请求失败则返回 "产生异常"
    """
    try:
        r = requests.get(url,timeout=1)  # 发送 HTTP GET 请求,可以通过timeout=1设置超时时间为 1 秒
        r.raise_for_status()  # 检查是否出现 HTTP 请求错误
        r.encoding = r.apparent_encoding  # 根据响应内容自动设置编码
        return r.text  # 返回 HTML 内容
    except:
        return "产生异常" 

if __name__ == "__main__":
 
    url1 = "https://www.baidu.com/"
    print(getHTMLText(url1))  # 成功输出HTML内容
    url2 = "https://chat.openai.com/"
    print(getHTMLText(url2))  # 产生异常
    first_time =  time.time()
    N = 100
    for i in range(0,N):
        getHTMLText(url1)
    last_time = time.time()
    print(f'访问{N}次耗时:{last_time-first_time}')  #访问100次耗时:9.285466194152832
    #可以看到request库性能较低
Robots协议

我们可以在网站的根目录建立一个robots.txt文件来说明限制爬虫的行为,但是这只是一种公示,不能真正阻止爬虫。

实例
  1. 当网站对访问用户设备有限制时,我们可以修改user-agent字段实现访问。
kv = {'user-agent':'Mozilla/5.0'}

r = requests.get(url,timeout=1,headers=kv) 

2.部分网站提供API URL 搜索

百度:http://www.baidu.com/s?wd

360:http://www.so.com/s?q

百度的我没有爬到,这里发下360的爬虫

import requests
url ='http://www.so.com/s'
keyword ='Python'
kv = {'q':keyword}
try:
    kv = {'q':keyword}
    r= requests.get(url,params = kv)
    r.raise_for_status()
    r.encoding= r.apparent_encoding
    print(r.text)
except:
    print('爬取失败')
  1. 存储
import requests  
import os        

url ='https://img-blog.csdnimg.cn/f35b24a8c05744dca042a64ef2154c12.png'  
root = "H:/pachong/"  # 图片保存的根目录
path = root + url.split('/')[-1]  # 图片保存的完整路径,使用URL中最后一个/后的文件名

try:
    if not os.path.exists(root):  # 如果根目录不存在,则创建
        os.makedirs(root)
    if not os.path.exists(path):  # 如果文件不存在,则执行以下操作
        r = requests.get(url) 
        with open(path,'wb') as f:  # 以二进制写入模式打开文件
            f.write(r.content)  # 二进制写入
            f.close()           
            print("文件已保存") 
    else:
        print("文件已存在")  
except:
    print('爬取失败')  

  1. ip归属地查询

我这里用的是ip38查询

import requests
url ='https://ip38.com/ip.php'
keyword ='ip-address'
kv = {'ip':keyword}
try:
    kv = {'ip':keyword}
    r= requests.get(url,params = kv)
    r.raise_for_status()
    r.encoding= r.apparent_encoding
    print(r.request.url)
    print(r.text)
except:
    print('爬取失败')

Beautiful Soup

  • 默认编码为UTF-8
基本使用
from bs4 import BeautifulSoup
import requests

url = 'https://baike.baidu.com/item/%E5%88%9D%E9%9F%B3%E6%9C%AA%E6%9D%A5/8231955'

try:
    r = requests.get(url)
    demo = r.text
    soup = BeautifulSoup(demo,"html.parser")		#html解析
    print(soup.prettify())	#添加缩进和换行符,使得文档的结构更加清晰易读。
except:
    print("error")
基本元素

基本元素说明

Tag标签,最基本的信息组织单元,分别用<>和</>标明开头和结尾
Name标签的名字,

的名字是’p’,格式:.name
Attributes标签的属性,字典形式组织,格式:.attrs
NavigableString标签内非属性字符串,<>…</>中字符串,格式:.string
Comment标签内字符串的注释部分,一种特殊的Comment类型
from bs4 import BeautifulSoup
import requests

url = 'https://python123.io/ws/demo.html'

try:
    r = requests.get(url)
    demo = r.text
    soup = BeautifulSoup(demo,"html.parser")
    #print(soup.prettify())
    print(soup.title)

    tag = soup.a
    print(tag)
    print(tag.name)
    print(tag.parent.name)
    print(tag.parent.parent.name)
    print(tag.attrs)
    print(tag.attrs['href'])
    print(type(tag))

    tag1 = soup.p
    print(soup.p.string)
    print(type(soup.p.string))
    

    print(soup.prettify())

    newsoup = BeautifulSoup("<b><!--This is a comment--></b><p>This is not a comment</p>","html.parser")
    print(newsoup.b.string)
    print(type(newsoup.b.string))
    print(newsoup.p.string)
    print(type(newsoup.p.string))
# 注意通过`.string`输出不会指出该类型为`comment`,所以我们要通过`type()`来判断是否为注释
except:
    print("error")
HTML内容遍历

分为下行遍历上行遍历平行遍历,直接看代码更容易理解

from bs4 import BeautifulSoup  # 导入BeautifulSoup库,用于解析HTML
import requests  # 导入requests库,用于发送HTTP请求

url = 'https://python123.io/ws/demo.html'  # 目标页面URL

try:
    r = requests.get(url)  # 发送GET请求获取页面内容
    demo = r.text  # 获取页面文本
    soup = BeautifulSoup(demo, "html.parser")  # 解析页面

    # 打印<head>标签的子节点
    print(soup.head.contents)

    # 打印<body>标签的子节点
    print(soup.body.contents)

    print("--------------------------------------------------------------------下行遍历---------------------------------------------------------------")

    # 使用.children属性遍历<body>标签的子节点
    for child in soup.body.children:
        print(child)

    # 打印<body>标签的子节点数量
    print(len(soup.body.contents))
    # 打印<body>标签的每个子节点
    for i in range(len(soup.body.contents)):
        print(soup.body.contents[i])

    print("--------------------------------------------------------------------------------------------------------------------------------------------")

    print("--------------------------------------------------------------------上行遍历---------------------------------------------------------------")
    
    # 遍历<a>标签的所有父节点
    for parent in soup.a.parents:
        if parent is None:
            print(parent)
        else:
            # 打印父节点的名称
            print(parent.name)

    print("--------------------------------------------------------------------------------------------------------------------------------------------")

    print("--------------------------------------------------------------------平行遍历---------------------------------------------------------------")

    # 打印<p>标签的文本内容
    print(soup.p)
    # 遍历<p>标签之后的所有兄弟节点
    for sibling in soup.p.next_siblings:
        print(sibling)

    print("#########################################################################################################################################") 

    # 遍历<p>标签之前的所有兄弟节点
    for sibling in soup.p.previous_siblings:
        print(sibling)

    print("--------------------------------------------------------------------------------------------------------------------------------------------")

except Exception as e:
    # 捕获异常并打印错误信息
    print("error:", e)

信息组织与提取

信息标记的三种方式

XML (eXtensible Markup Language)

  • 最早的通用信息标记语言,可扩展性好,但繁琐
  • Internet上的信息交互与传递
<person>
<firstName>Tian</firstName>
<lastName>Song</lastName>
<address>
<streetAddr>中关村南大街5号</streetAddr>
<city>北京市</city>
<zipcode>100081</zipcode>
</address>
<prof>Computer System</prof><prof>Security</prof>
</person>

JSON (JavaScript Object Notation)

  • 信息有类型,适合程序处理(js),较XML简洁

  • 移动应用云端和节点的信息通信,无注释

{
“firstName” : “Tian” ,
“lastName” : “Song” ,
“address” : {
“streetAddr” : “中关村南大街5号” ,
“city” : “北京市” ,
“zipcode” :100081} ,
“prof” : [ “Computer System” , “Security” ]

YAML (YAML Ain't Markup Language)

  • 信息无类型,文本信息比例最高,可读性好

  • 各类系统的配置文件,有注释易读

firstName : Tian
lastName : Song
address :
streetAddr : 中关村南大街5号
city : 北京市
zipcode : 100081
prof :
‐Computer System
‐Security
信息提取
from bs4 import BeautifulSoup  
import requests  
import re  

url = 'https://python123.io/ws/demo.html'  

try:
    r = requests.get(url)  # 发送GET请求获取页面内容
    demo = r.text  # 获取页面文本
    soup = BeautifulSoup(demo, "html.parser")  # 使用BeautifulSoup解析页面

    # 查找所有<a>标签并打印其href属性值
    print("-----------------")
    for link in soup.find_all('a'):
        print(link.get('href'))
    print("-----------------")
    print()

    # 查找所有标签名,并打印出每个标签的名称
    print("-----------------")
    for tag in soup.find_all(True):
        print(tag.name)
    print("-----------------")
    print()

    # 使用正则表达式查找标签名中含有'b'的所有标签,并打印出标签名
    print("-----------------")
    for tag in soup.find_all(re.compile('b')):
        print(tag.name)
    print("-----------------")
    print()

    # 根据id属性值查找标签,并打印出符合条件的标签
    print("-----------------")
    for tag in soup.find_all(id='link1'):
        print(tag)
    print("-----------------")
    for tag in soup.find_all(id=re.compile('link')):
        print(tag)
    print("-----------------")
    print()

    # 查找所有<a>标签及其子孙节点,并打印出每个标签
    print("-----------------")
    print(soup.find_all('a'))
    print("-----------------")

    # 只在当前层级查找<a>标签,并打印出每个标签
    print(soup.find_all('a', recursive=False))
    print("-----------------")
    print()

    # 根据文本内容查找标签,并打印出符合条件的标签
    print("-----------------")
    print(soup.find_all(string="Basic Python"))
    print("-----------------")
    print(soup.find_all(string=re.compile('Python')))
    print("-----------------")

except Exception as e:
    # 捕获异常并打印错误信息
    print("error:", e)

拓展方法

方法说明

  • <>.find() 搜索且只返回一个结果,同.find_all()参数
  • <>.find_parents() 在先辈节点中搜索,返回列表类型,同.find_all()参数
  • <>.find_parent() 在先辈节点中返回一个结果,同.find()参数
  • <>.find_next_siblings() 在后续平行节点中搜索,返回列表类型,同.find_all()参数
  • <>.find_next_sibling() 在后续平行节点中返回一个结果,同.find()参数
  • <>.find_previous_siblings() 在前序平行节点中搜索,返回列表类型,同.find_all()参数
  • <>.find_previous_sibling() 在前序平行节点中返回一个结果,同.find()参数

中国大学排名定向爬虫实例

这里使用的是2023版的排名,8年过去网页结构已发生变化,稍加修改还能继续爬取【软科排名】2023年最新软科中国大学排名|中国最好大学排名 (shanghairanking.cn)

from bs4 import BeautifulSoup
import bs4
import requests


def getHTMLText(url):
    """
    获取指定URL的HTML文本内容

    参数:
    url (str): 目标网页的URL

    返回:
    str: 网页的HTML内容,如果请求失败则返回空字符串
    """
    try:
        r = requests.get(url, timeout=30)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return ""


def fillUnivList(ulist, html):
    """
    将HTML文本中的大学信息填充到列表中

    参数:
    ulist (list): 存储大学信息的列表
    html (str): 网页的HTML内容
    """
    soup = BeautifulSoup(html, "html.parser")
    for tr in soup.find('tbody').children:
        if isinstance(tr, bs4.element.Tag):			 #是否为标签元素
            tds = tr('td')
            a = tds[0].string.strip()
            b = tds[1].find('a', class_='name-cn').string.strip()	#大学名
            c = tds[1].find('p').string.strip()	#985还211还是双一流 
            d = tds[2].text.strip()	#地域,不能用stirng,返回了none,这里用text
            e = tds[3].text.strip()	#类型
            f = tds[4].string.strip()	#总分,text和string类型都可以
            ulist.append([a, b, c, d, e, f])


def printUnivList(ulist, num):
    """
    打印大学信息列表

    参数:
    ulist (list): 存储大学信息的列表
    num (int): 打印的大学数量
    """
    tplt = "{:^20}\t{:^20}\t{:^20}\t{:^20}\t{:^10}\t{:^10}"
    print(tplt.format("排名", "学校名称", "级别", "地域", "类型", "总分"))
    for i in range(num):
        u = ulist[i]
        print(tplt.format(u[0], u[1], u[2], u[3], u[4], u[5]))


def main():
    """
    主函数,用于执行爬虫程序
    """
    uinfo = []
    url = 'https://www.shanghairanking.cn/rankings/bcur/202311'
    html = getHTMLText(url)
    fillUnivList(uinfo, html)
    printUnivList(uinfo, 30)


main()

  • 16
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值