您现在的位置是:首页 >其他 >Python_正则_爬虫_子网划分程序网站首页其他
Python_正则_爬虫_子网划分程序
正则表达式
正则表达式在Python中,它被内嵌在了re模块里面
. 通配符 代表匹配除 后的任意字符。
^ 起始锚定符 代表被匹配的字符串必须以某个子串开头,只检测开头。
$ 结束锚定符 代表被匹配的字符串必须以某个子串结尾,只检测结尾。
不论成功或者失败都会返回
* 重复符 代表可以取0到无穷位
+ 重复符 代表可以取1到无穷位
? 重复符 代表可以取0到1位
{n} 重复符 精确匹配n个前面的表达式
{n,m} 重复符 代表匹配n到m次由前面的正则表达式定义的片段
上述(默认贪婪取值,可通过?取消贪婪模式)
取消贪婪模式就是取最小
*?就是0
+?就是1
??就是0
[] 字符集 其本身代表或的作用 [ab]代表a或者b。 ’
在字符集中上面的方法均失去原本含义。但 - ^ 可以在字符集中使用
[-] 字符集中的 - 号代表可以取从多少到多少区间的值。
[^] 字符集中的 ^ 号代表 非 的作用。比如[^0-9]就是说这一位数并非数字
[] 转义符
d 匹配任何十进制数,它相当于在字符集中使用[0-9]
D 匹配任何非十进制数,它相当于在字符集中使用[^0-9]
s 匹配任何空白字符,它相当于在字符集中使用[ fv]
S 匹配任何非空白字符,它相当于在字符集中使用[^ fv]
w 匹配任何字母数字下划线字符,它相当于在字符集中使用[a-z A-Z 0-9]
W 匹配任何非字母数字下划线字符,它相当于在字符集中使用[a-z A-Z 0-9]
匹配一个特殊字符边界,比如空格,&.#等(不常用)
A 匹配字符串开始(不常用)
匹配字符串结束,如果存在换行则只匹配换行前的字符(不常用)
z 匹配字符串结束(不常用)
G 匹配最后匹配完成的位置(不常用)
匹配一个换行符(不常用)
匹配一个制表符(不常用)
f 匹配一个分页符(不常用)
转义字符
简易爬虫
使用爬虫的时候不能使用代理或者vpn,因为使用代理可以帮助我们隐藏真实 IP 地址,从而保护个人隐私和安全,同时也可以绕过某些限制或者封锁。因此,很多非法爬虫程序都使用代理来进行访问。
爬取豆瓣top250电影网站的图片,这个是很久之前写的,发现网站的源代码有变化,要小改一下
豆瓣电影海报
import os
import re
import requests
url = 'https://movie.douban.com/top250'
# 正规一点的网站都有反爬机制,要加headers
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.58'}
response = requests.get(url, headers=headers).text
# print(response)可以看看是否爬到源代码
# 对源代码进行人眼解析,看看那些是我们想要的
pattern1 = re.compile(r'alt="(.*)" src="(.*)" class')
response_img = pattern1.findall(response)
print(response_img)
pattern2 = re.compile('(.*?)"')
if not os.path.exists('D:电影图片'):
os.mkdir(r'D:电影图片')
for title, image_url, in response_img:
print(image_url)
print(title)
image_content = requests.get(image_url).content
# print(image_content)
with open('D:电影图片' + '\' + title + '.jpg', 'wb') as fw:
print('正在保存《' + title + '》图片')
fw.write(image_content)
拿到源代码需要人眼解析拿到自己想要的资源部分,需要花时间了解网页资源结构
例如网易云音乐文件url为
http://music.163.com/song/media/outer/url?id= + 歌曲id
网易云音乐热歌榜单
import os
import requests
import re
# 网易云网址,以热歌榜单链接为例
url = "https://movie.douban.com/celebrity/1045259/photos/"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.58'}
response = requests.get(url, headers=headers).text
# 正则匹配网易云歌曲ID、歌曲名字
# <li><a href="/song?id=1968781675">一直很安静</a>
zip_data = re.findall('<li><a href="/song?id=(.*?)">(.*?)</a></li>', response)
print(zip_data) # 打印查看
# 爬取音乐函数
def craw(music_url, music_name):
music_data = requests.get(music_url, timeout=30).content
# 新建一个文件夹
if not os.path.exists('D:/网易云热歌'):
os.mkdir('D:/网易云热歌')
# 保存数据
with open(f"D:/网易云热歌/{music_name}.mp3", 'wb') as f:
f.write(music_data)
if __name__ == '__main__':
for music_id, music_name in zip_data:
print('开始下载歌曲{}...'.format(music_name))
# 网易云外播链接
music_url = "http://music.163.com/song/media/outer/url?id=" + music_id
# print(music_url)
craw(music_url, music_name)
print('歌曲{}下载完成'.format(music_name))
qq音乐也有但是比较麻烦,有各种各样的序列,
http://dl.stream.qqmusic.qq.com/ + 很多序列 C400002202B43Cq4V4.m4a?guid=(全局唯一标识符?不确定)&vkey=(音频文件的验证密钥,用于验证用户是否有权访问该音频文件)&uin=(QQ号)&fromtag=(请求来源标识符,区分网页访问、移动端访问、第三方应用访问)
QQ 音乐版权多,可能会对 vkey 的计算方法进行更新和调整,因此在爬取数据时需要更新,以确保能够正确获取音频文件。因为我是会员进入访问的,可能不是会员有些歌曲就不能访问。
这个可能会泄露我的个人信息,就不放代码了,我没写,网上有:)
爬取图片(webp jpg后缀文件)函数
网站使用了WebP格式的图片来提高页面加载速度和降低带宽消耗,但是在Python爬虫中获取到的图片是服务器原始的格式,可能是JPEG格式的。这是因为Python爬虫只是获取了图片的二进制数据,而没有对图片格式进行转换。
import os
import requests
import re
# 网易云网址,以热歌榜单链接为例
url = "https://music.163.com/discover/toplist?id=3778678"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.58'}
response = requests.get(url, headers=headers).text
# 正则匹配网易云歌曲ID、歌曲名字
# <li><a href="/song?id=1968781675">一直很安静</a>
zip_data = re.findall('<li><a href="/song?id=(.*?)">(.*?)</a></li>', response)
print(zip_data) # 打印查看
# 爬取音乐函数
def craw(music_url, music_name):
music_data = requests.get(music_url, timeout=30).content
# 新建一个文件夹
if not os.path.exists('D:/网易云热歌'):
os.mkdir('D:/网易云热歌')
# 保存数据
with open(f"D:/网易云热歌/{music_name}.mp3", 'wb') as f:
f.write(music_data)
if __name__ == '__main__':
for music_id, music_name in zip_data:
print('开始下载歌曲{}...'.format(music_name))
# 网易云外播链接
music_url = "http://music.163.com/song/media/outer/url?id=" + music_id
# print(music_url)
craw(music_url, music_name)
print('歌曲{}下载完成'.format(music_name))
lxml及beautifulsoup
lxml
是一个 Python 库,用于处理 XML 和 HTML 文档。它提供了与标准库 xml.etree.ElementTree
类似的 API,但性能更好。lxml
还提供了额外的功能,例如支持 XPath 和 CSS 选择器。
lxml 解析 XML
<?xml version="1.0"?>
<root>
<element id="1">
<child>Text 1</child>
</element>
<element id="2">
<child>Text 2</child>
</element>
</root>
# 不知道为什么,安装在D盘的PyCharm我得添加安装在C盘的lxml路径才能使用
import sys
sys.path.append("C:\users/henry/appdata/roaming/python/python37/site-packages")
from lxml import etree
# 从文件读取 XML 文档
with open("sample.xml", "r") as file:
xml_content = file.read()
# 解析 XML 文档
root = etree.fromstring(xml_content)
# 遍历所有 element 节点
for element in root.findall("element"):
element_id = element.get("id")
child_text = element.find("child").text
print(f"Element ID: {element_id}, Child Text: {child_text}")
# Element ID: 1, Child Text: Text 1
# Element ID: 2, Child Text: Text 2
lxml
支持 XPath 表达式,这使得在 XML 或 HTML 文档中查找元素变得非常方便
from lxml import etree
# 从文件读取 XML 文档
with open("sample.xml", "r") as file:
xml_content = file.read()
# 解析 XML 文档
root = etree.fromstring(xml_content)
# 使用 XPath 查找所有 element 节点
elements = root.xpath("//element")
for element in elements:
element_id = element.get("id")
child_text = element.xpath("./child/text()")[0]
print(f"Element ID: {element_id}, Child Text: {child_text}")
# Element ID: 1, Child Text: Text 1
# Element ID: 2, Child Text: Text 2
lxml 解析 HTML
<!DOCTYPE html>
<html>
<head>
<title>Sample HTML</title>
</head>
<body>
<h1>Welcome to the website!</h1>
<p>Here are some useful links:</p>
<ul>
<li><a href="https://www.example1.com">Example 1</a></li>
<li><a href="https://www.example2.com">Example 2</a></li>
<li><a href="https://www.example3.com">Example 3</a></li>
</ul>
</body>
</html>
import sys
sys.path.append("C:\users/henry/appdata/roaming/python/python37/site-packages")
from lxml import html
# 从文件读取 HTML 文档
with open("sample.html", "r") as file:
html_content = file.read()
# 解析 HTML 文档
root = html.fromstring(html_content)
# 提取所有链接
links = root.xpath("//a/@href")
for link in links:
print(link)
# https://www.example1.com
# https://www.example2.com
# https://www.example3.com
子网划分
和正则无关,仅仅是心血来潮
这个我分别用chatGPT3.5和4,都难以获得能够正确运行的代码
越是描述问题,它就越乱来,越改越乱。
之后发现要尽量引用出问题的代码或者变量
但是反而3.5的代码我改改能用,但是会有输出多个子网号相同的子网的问题。
将程序发给GPT4,并描述问题,最好一次只改一个问题,因为结果还是有子网号全0的情况,由于我一天只有一次机会,所以就不改了。
import math
import ipaddress
def subnet_calculator(class_type, subnetnum, host_counts):
if class_type not in ['A', 'B', 'C']:
raise ValueError("只能在标准网ABC里选")
base_prefix = {'A': 8, 'B': 16, 'C': 24}
subnets = []
for i, host_count in enumerate(host_counts):
# 需要的主机位数
needed_bits = math.ceil(math.log2(host_count + 2))
# 网络位
subnet_mask = 8 - needed_bits
# 前缀
network_prefix = base_prefix[class_type] + subnet_mask
# 生成子网地址
subnetnum_int = int(ipaddress.IPv4Address(subnetnum))
subnetnum_int += (1 << (32 - network_prefix)) * i
subnet_address = ipaddress.IPv4Address(subnetnum_int)
# 检查子网地址是否重复或全0/全1
while any(subnet['subnet_address'].split('/')[0] == str(subnet_address) for subnet in subnets) or
subnet_address.is_unspecified or subnet_address.is_reserved:
subnetnum_int += (1 << (32 - network_prefix))
subnet_address = ipaddress.IPv4Address(subnetnum_int)
subnet = {
'subnet_address': f'{subnet_address}/{network_prefix}',
'subnet_mask': str(ipaddress.IPv4Network((subnet_address, network_prefix), strict=False).netmask),
'host_range': (str(ipaddress.IPv4Network((subnet_address, network_prefix), strict=False)[1]),
str(ipaddress.IPv4Network((subnet_address, network_prefix), strict=False)[-2]))
}
subnets.append(subnet)
return subnets
# 示例输入
class_type = 'C'
subnetnum = '192.168.1.0'
host_counts = [20,6]
# 计算子网信息
subnet_info = subnet_calculator(class_type, subnetnum, host_counts)
# 打印结果
for i, subnet in enumerate(subnet_info):
print(f"子网 {i + 1}:")
print(f"子网地址: {subnet['subnet_address']}")
print(f"子网掩码: {subnet['subnet_mask']}")
print(f"主机范围(包括网关): {subnet['host_range'][0]} - {subnet['host_range'][1]}")
print()
# 结果;
# 子网 1:
# 子网地址: 192.168.1.0/27
# 子网掩码: 255.255.255.224
# 主机范围(包括网关): 192.168.1.1 - 192.168.1.30
# 子网 2:
# 子网地址: 192.168.1.8/29
# 子网掩码: 255.255.255.248
# 主机范围(包括网关): 192.168.1.9 - 192.168.1.14