网络架构
1.1互联网工作原理
- IP 地址:任何连接网络的计算机都需要一个唯一的地址标记它
IP地址由四部分被分隔的数字序列组成,如:192.129.2.10,取值范围在0到255 - 域名: IP地址的别名,使其更容易记忆
- 搜索引擎与浏览器的区别
- 浏览器是一个接受并显示网页的软件
- 搜索引擎是一个帮助用户搜索其他网页的网站
1.2网站三大支柱
HTTP/HTTPS
- 定义:一种 超文本传输协议
- 请求过程:
- 用户在浏览器输入网址,浏览器向网页服务器发送请求
- 网页服务器接到请求,处理请求,产生响应
- 浏览器接受网页服务器的HTML内容,渲染展示给用户
- **HTTP安全吗?
- 明文传输,易被窃听或篡改,不够安全
- 解决方法:HTTPS 在HTTP基础上加上SSL/TLS协议,依靠SSL证书来验证服务器身份,确保数据传输安全
URL
俗称网址
url的组成
以此为例:
http://www.example.com:80/path/to/myfile.html?key1=value1&key2=value2#SomewhereInTheDocument
- HTTP是协议
- www.example.com 是域名
- :80是端口
- path/to/myfile.html是网络服务器上的资源路径
- key1=value1&key2=value2是提供给网络服务器的额外参数
- #SomewhereInTheDocument 是资源本身的另一部分锚点,类似于书签,用来为浏览器显示位于该书签位置的内容和方向
HTML
- 超文本标记语言
- 组成:<开始标签>被标记的内容<结束标签/>
- 元素:开始结束加被标记内容就是一个完整的元素
- 空元素:只有一个标签用来在该位置插入一些东西
术语区分
| 术语 | 含义 |
|---|---|
| IP地址 | 唯一标识互联网计算机的逻辑地址 |
| 域名 | IP地址的别名,方便记忆 |
| URL | 俗称网址,格式为<协议>://<域名/IP>:<端口号/路径> |
网络爬虫概述
2.1网络爬虫
- 定义:自动提取网页的程序,主要目的是将互联网上的网页下载到本地,并 提取相关数据
- 网络爬虫工作流程 ![[网络爬虫工作流程.png]]
2.2网络爬虫的类型
1. 通用网络爬虫——从一些种子URL扩充到整个Web
- 全网爬虫流程![[全网爬虫流程.png]]
- 实用范围:主要为 搜索引擎和大型web服务商采集数据。爬行范围和数量巨大,对 爬行速度和储存空间要求高,对 爬行页面顺序要求低,通常采用 并行工作方式。
- 通用网络爬虫真的通用吗? 有哪些局限性?
- 包含大量用户不需要的网页
- 不能很好的获取 信息密集的数据
- 基于关键字检索,一般不支持语义信息查询和 搜索引擎智能化
2.聚焦网络爬虫——选择性爬取相关主题页面
- 主题网络爬虫流程![[主题网络爬虫流程.png]]
- 优点:节省爬虫时所需的带宽资源和服务器资源
- 特点:按照预先定义好的主题 有选择的进行爬取,相较于 通用爬虫,增加了 目标的定义和 过滤机制
3.增量式网络爬虫——只爬取新/变化的网页
- 优缺点:有效减少下载量,及时更新已爬网页,减小时间和空间消耗。但 增加爬行算法的复杂度和实现难度
4.深层网络爬虫——爬取隐藏的深层页面
- 深层页面是 指普通搜索引擎难以发现的信息内容页面,信息量更多,质量更高。
- 流程:解析url -> 分析页面是否包含深层页面入口的表单 -> 模拟人的行为对表单进行分析填充提交
2.3反爬机制
为什么要有反爬机制?
- 不愿自己数据被别人免费获取
- 简单爬虫数据采集速度快,可能会因为 请求太多,造成网站服务器不能正常工作
网络爬虫基础
requests 库
# 导入requests库
import requests
response = requests.get(url,params,headers,cookies,auth,timeout)
print(response.text) #返回文本
print(response.content) #返回二进制数据
response1 = requests.post(url,data = {key:value},json = {key:value},args)
参数
get:
url - 请求对象的URL地址
params - get请求的参数
headers - 请求头信息
cookies - 客户端记录的用户身份信息的参数
auth - authobject启用基本http身份验证(没用到过)
timeout - 请求超时的设置,浮点数表示
post:
data - 要发送到指定url的字典、元组、列表或文件对象
json - 发送给指定url的json对象
args - 其他参数,如cookies、headers、verify等
Cookie与Session
cookie:通过在 客户端 记录的信息确定用户的身份
session:通过在 服务器 端记录的信息确定用户的身份
常见的响应状态码
- 200——请求成功
- 301——资源被永久转移
- 307——浏览器内部重定向
- 401——需要出入账号和密码访问资源
- 403——请求被禁止
- 404——请求资源不存在
- 500——内部服务器错误
- 418——网站发现你是爬虫
服务器端渲染 VS 客户端渲染
- 服务器端渲染:返回前端 完整的HTML文件 浏览器拿到html后直接解析展示
- 客户端渲染:前后端分离的开发模式,后端不提供完整的html页面,而是提供一些api使得前端可以获取json数据(通过Ajax请求 ),拿给前端拼接,最后展示在浏览器,好处是前端专注ui开发,后端专注逻辑开发
- Ajax请求:异步从服务器请求数据更新到网页
python读写
with open(文件名,打开方式) as f: #'r'只读,'w'只写,会覆盖前面写的。用with open不需要考虑关闭文件的事,自动关闭
反爬机制和反反爬策略
- 常见的反爬机制
IP封锁,验证码验证,ua检测,js数据加密等 - 策略
- IP代理:绕过封锁
- ua伪装:模拟浏览器
- 请求延迟:模仿用户操作
- 数据解析技巧:高校提取信息
- cookie和session跟踪:添加cookie参数
美丽汤BeautifulSoup
特点
- api简单,功能强大
- 支持多种解析器
- 自动实现编码转换
补充:解析器:把某种格式的文本转换成某种数据结构
基本使用
# 导入
from bs4 import BeautifulSoup
# 初始化beautifulsoup类
soup = BeautifulSoup(html,'解析器')
选择器
- 节点选择器
# tag对象:<tag对象>
soup.tag # 有多个相同节点值返回第一个
#返回节点元素
soup.tag.name # 返回字符串,tag对象的名称
soup.tag.attrs # 返回字典,<tag 属性>,返回属性
soup.tag.string # 返回字符串,tag里面标记的内容
#嵌套选择
# <tag><tag2>text</tag2></tag>
soup.tag.tag2
- css选择器
soup.select()
#'.'类选择器
#'#'id选择器
#标签选择器
# id选择器 - 用#定位元素 以id定位第一个ul节点
print(soup.select('#list-1'))
# 类选择器 - 用.定位元素 以class定位第二个ul节点
print(soup.select('.list-small'))
# 标签选择器 - 使用标签名定位元素 以标签名定位ul节点
print(soup.select('ul'))
# 定位class属性值为list,同时id属性值为list-1的所有节点
print(soup.select('.list' '#list-1'))
# 定位第一个ul节点的子级li节点
print(soup.select('#list-1 .element'))
- 方法选择器
soup.find_all(name,attrs,kwargs,text,limit,recursive) #返回所有
soup.find #返回第一个
name参数用来接收tag名称,有四种形式:字符串,正则,列表和True
attrs参数用来接收属性的键值对字典
kwargs参数用来接收常用属性的变量赋值的形式 例如:id=‘link1’ ,class_=“sister”
text参数用来接收文本信息
limit参数用来限制返回结果的数量
recursive参数用来决定是否获取子孙节点
总结
原理 1. 实例化beautifulsoup对象,并将页面源代码加载到该对象中去
2.通过bs对象的相关属性方法进行标签定位和数据提取
如何实例化?
1. 将本地html文档加载到对象中去
2. 将互联网获取的页面源码加载到对象中(两种方法) soup
BeatifulSoup(page_text,‘lxml’) bs的属性和方法
3. soup.tagname
(tagname代表标签名,如soup.div等等)
2.soup.find()
(1)soup.find(‘div’) = soup.div
(2)属性定位soup.find(‘标签名’,标签属性(如:class_等)=‘具体参数’)
3.soup.find_all(‘标签名’) 符合标准的所有标签名
4.soup.select(‘’)返回为列表。
(1)引号内填某种选择器(类选择器等)如:class,id,等
(2)层级选择器’>‘代表一个层级,’ '表示多个层级。
5.获取标签之间的文本数据:
(1)soup.a.text/string/get_text()其中text和get_text()可以获得标签的所有内容,string只能得到直系标签的内容
6.获取标签的属性值
soup.a['属性']
CSV文件写入
- 列表写入
import csv
header = ['姓名', '年龄', '城市']
data = [
['小明', '25', '北京'],
['小红', '30', '上海']
]
with open('data.csv', 'w', encoding='utf-8', newline='') as f:
writer = csv.writer(f) # 创建writer对象
writer.writerow(header) # 写入单行(标题)
writer.writerows(data) # 写入多行数据(嵌套列表)
- 字典写入
import csv
fieldnames = ['姓名', '年龄', '城市'] # 定义字段名(表头)
data = [
{'姓名': '小明', '年龄': '25', '城市': '北京'},
{'姓名': '小红', '年龄': '30', '城市': '上海'}
]
with open('data.csv', 'w', encoding='utf-8', newline='') as f:
writer = csv.DictWriter(f, fieldnames=fieldnames) # 创建DictWriter对象
writer.writeheader() # 写入表头
writer.writerows(data) # 写入多行数据
正则表达式
常用元字符
| \d | 匹配任意数字,等价于[0-9] |
|---|---|
| \w | 匹配任意字母数字及下划线 |
| \W | 非字母数字下划线 |
| \s | 匹配任意的空白符 |
| \n | 匹配一个换行符 |
| \t | 匹配一个制表符 |
| \D | 非数字 |
| \S | 非空白符 |
| . | 匹配除换行符以外的任何字符 |
| ^ | 匹配字符串的开始 |
| $ | 匹配字符串的结尾 |
| a|b | 匹配a或b |
| [···] | 匹配字符组中的字符 |
| [^···] | 匹配非字符组的字符 |
常用量词
| 量词作用 | 控制元字符出现次数 |
|---|---|
| * | 重复0次或多次 |
| + | 重复1次或多次 |
| ? | 重复0次或1次 |
| {m} | 重复m次 |
| {m,} | 重复m次或更多次 |
| {m,n} | 重复m到n次 |
- .**: 贪婪匹配
- .*?*:惰性匹配
正则表达式语法
re.match()——尝试从字符串的 起始位置匹配 一个模式,如果不是起始位置匹配成功返回 none
import re
re.match(pattern,string,flags = 0)
| 参数 | 描述 |
|---|---|
| pattern | 匹配的正则表达式 |
| string | 匹配的字符串 |
| flags | 标志位,用于控制正则表达式的匹配方式,如:是否区别大小写、多行匹配等等 |
| repl | 替换的字符串,也可以是一个函数 |
| count | 模式匹配后替换的最大次数,默认0表示替换所有的匹配 |
- re.search()——只要有匹配的后面就不再继续检索,找到一个匹配的就停止
import re
re.search(pattern,string,flags = 0)
re.findall()——在字符串中找到正则表达式所匹配的 所有子串,返回 一个列表,如果有多个匹配模式,返回 元组列表,没有匹配就返回 空列表
import re
re.findall(pattern,string,flags = 0)
re.compile()——用于函数编译正则表达式,生成一个正则表达式(pattern)对象(预加载),供match(),search(),findall()等函数使用
re.compile(pattern)
# 其他方法的调用方法改变,如:
re.findall(string,flags = 0)
re.sub()
re.sub(pattern,repl,string,count = 0,flags = 0)
flags的参数
| 参数 | 意义 |
|---|---|
| re.I | 忽略大小写 |
| re.S | 单行模式 |
| re.M | 多行模式 |
- (?P<组名>正则表达式):正则提取/分组匹配
补充pythony 异常处理
try:
正常操作
except:
发生异常,执行这块代码
else:
如果没有异常执行这块代码
2547

被折叠的 条评论
为什么被折叠?



