爬虫框架Scrapy学习笔记-1

前言

在现代互联网时代,网页数据获取和处理已经成为了重要的技能之一。无论是为了获取信息、做市场研究,还是进行数据分析,掌握网页爬取和数据处理技术都是非常有用的。本文将介绍从网页加载到数据存储的完整过程,包括网络请求、数据解析、反爬措施、多任务异步爬虫、数据存储和面向对象编程等内容。通过本文的学习,读者将能够掌握从网页上收集信息的基本原理和技术,以及如何将这些信息进行处理和存储。

文章目录

  • 前言
  • 网页加载的全过程
  • 网页加载的渲染的两种形式:
  • Network面板中的各部分:
  • requests库的用法:
    • 安装
    • GET请求
      • 百度搜索实例
    • POST请求
      • 两种不同实例
  • HTTP状态码
  • 简单的反爬操作:
    • **请求头:**
    • **响应头:**
    • requests.Session的用法:
      • 创建Session对象
      • 设置请求头
      • 设置Cookies
      • 发送请求
      • 关闭Session
  • 数据解析方法
    • 三种解析HTML数据的方法:
    • json和jsonp的解析方法:
  • 多任务异步爬虫.多线程,多进程,协程异步I/O
    • 多线程
    • 多进程
    • 协程异步I/O
  • 数据存储
    • CSV
    • MySQL
    • MongoDB
    • Redis
  • 面向对象编程
    • 编程思想的转变
    • 面向对象思维
    • 创建对象
  • 总结

网页加载的全过程

假设我们在浏览器输入www.example.com这个网址并回车,会发生以下过程:

  1. 浏览器检查本地缓存,看看这个网页是否访问过,如果访问过就直接显示本地缓存内容,不用再到服务器请求。
  2. 如果没有本地缓存,浏览器就创建一个HTTP请求,请求www.example.com这个服务器上的网页。
  3. 请求发出去,服务器接收到请求后查找网页文件,找到后把网页文件的内容放入HTTP响应返回给浏览器。
  4. 浏览器接收到服务器返回的HTML内容,就像得到一块土豆一样,先要洗干净、切块,才能烹饪。浏览器也要解析HTML、CSS、JS,才能显示出漂亮的界面。
  5. 浏览器会生成DOM树来存储HTML标签结构,生成CSSOM树来存储CSS样式规则。
  6. 浏览器执行页面的JavaScript代码,这可能会修改DOM或CSSOM。
  7. 浏览器会将DOM和CSSOM整合形成一棵渲染树,确定每个节点的样式和坐标。
  8. 按渲染树来布局,计算每个节点的大小和位置,然后把页面绘制出来。
  9. 把绘制好的页面显示在浏览器窗口。
  10. 当我们点击、输入时,浏览器会实时响应,重新执行JavaScript、调整样式、重新布局、重绘页面。

我用通俗易懂的语言,详细再给你解释一遍网页的加载过程:

  1. 小明输入网址,按下回车键,浏览器听到后开始工作。
  2. 浏览器先看看小明是不是之前来过这个网站,如果来过就拿出旧网页给小明看。
  3. 如果没来过,浏览器就给网站服务器发个邮件,说想看看你家的网站,请把网页的内容回复我。
  4. 网站服务器收到浏览器的邮件,找到网页文件后封入信封回邮给浏览器。
  5. 浏览器收到服务器的回信,把信封打开,里面是一堆代码和图片之类的。
  6. 浏览器把这些代码和图片像积木一样拼在一起,先建立一个DOM树结构,再确定CSS样式,然后把两棵树合成一棵渲染树。
  7. 浏览器按渲染树计算每个部分的位置和大小,然后把网页画出来。
  8. 把画好的网页拿给小明看,小明开心地浏览网页了。
  9. 如果小明点击网页或者输入内容,浏览器会重新执行代码,重绘页面。

网页加载的渲染的两种形式:

  1. 服务器端渲染
  • 服务器收到客户端请求后,使用服务器语言(如PHP)生成整合了数据的HTML内容。
  • 这样浏览器拿到的源代码中已经包含了需要展示的数据。
  1. 客户端渲染
  • 浏览器拿到服务器返回的HTML源代码后,开始解析和渲染。
  • 通过执行JavaScript代码,可以实现网页的动态效果和交互。
  • 数据和页面内容的整合在浏览器本地完成。
  • 这样的渲染方式需要通过F12-network,在Fetch/XHR或JS中寻找需要的数据。
  • preserver log可以记录你访问过的页面,打钩可避免网页302,重定向造成的影响

区分服务器端和客户端渲染非常重要。服务器端渲染可以减轻客户端压力,客户端渲染可以提供更好的交互体验。现代网页开发通常会结合两种渲染方式的优点。

Network面板中的各部分:

  1. Headers
    请求头和响应头,显示了请求和响应的所有HTTP头信息,包括通用头和自定义头。重要的头会展开显示,如User-Agent, Cookie, Referer等。
  2. Payload
    请求Payload显示发送给服务器的数据体,比如POST请求的表单数据或JSON体。
    响应Preview显示接收到的响应结果内容,比如HTML代码,图片文件,JSON数据等。
  3. Cookies
    请求Cookies显示请求头中Cookie相关信息。
    响应Cookies显示响应头设置的Cookie内容。
    可查看Cookie的传递过程。
  4. Initiator
    显示发起该请求的资源信息,比如HTML标签引入的img/script/link等。
    可了解资源之间的依赖关系。
  5. Timing
    累积持续时间:整个请求过程总计耗时。
    块级别时间明细:分别显示队列、域名解析、TCP连接、TLS安全连接、请求响应等每个阶段的耗时。
    方便找出性能瓶颈。
  6. Response
    显示响应状态码(200, 404等)和响应来源(服务端响应,浏览器缓存等)
    可快速识别请求是否成功。
  7. 筛选条件
    可按方法,域名,类型,文本等条件进行过滤,组合使用可保存筛选条件。

requests库的用法:

安装

pip install requests

GET请求

GET请求用于获取服务器的数据。它通过URL的参数传递请求数据。

import requestsparams = {'key1': 'value1', 'key2': 'value2'}response = requests.get('http://httpbin.org/get', params=params)
print(response.url)
# http://httpbin.org/get?key1=value1&key2=value2

requests会将params字典类型自动转换为url参数。
也可以直接将参数拼接到url中:

import requestsresponse = requests.get('http://httpbin.org/get?key1=value1&key2=value2') 

百度搜索实例

https://www.baidu.com/s?tn=85070231_38_hao_pg&wd=总结
https://www.baidu.com/s?tn=85070231_38_hao_pg&wd=%E6%80%BB%E7%BB%93
params = {‘tn’: ‘85070231_38_hao_pg’, ‘wd’: ‘总结’}
在这里插入图片描述

POST请求

POST请求用于向服务器发送数据。它通过请求体传递参数。

import requestsdata = {'key1': 'value1', 'key2': 'value2'}response = requests.post('http://httpbin.org/post', data=data)
print(response.text)
# {
#   "form": {
#     "key1": "value1",
#     "key2": "value2"
#   }
# }

requests会自动编码data字典为表单格式。
也可以直接传递字符串:

data = 'key1=value1&key2=value2'
response = requests.post('http://httpbin.org/post', data=data)

此外,还可以传递JSON数据:

import jsondata = {'key1': 'value1', 'key2': 'value2'}
data = json.dumps(data) response = requests.post('http://httpbin.org/post', data=data)

两种不同实例

Form Data形式
http://www.xinfadi.com.cn/priceDetail.html data = {‘key1’:‘value1’, ‘key2’: ‘value2’}

response = requests.post(‘http://httpbin.org/post’, data=data)
传递字典即可
在这里插入图片描述

Request Payload形式
能直观的看到是json类型的数据
两种方案

  1. requests.post(url,json={字典})
  2. requests.post(url,data=json.dumps({字典}),
    headers={ “Content-Type” : “application/json; charset=UTF-8” })
    在这里插入图片描述

HTTP状态码

  1. 200系列 - 请求成功,表示服务器成功处理了请求。常见有:
  • 200 OK - 一般请求成功返回此代码
  • 204 No Content - 请求成功但无内容返回
  1. 300系列 - 重定向,表示资源已被分配了新的URI。常见有:
  • 301 Moved Permanently - 永久重定向
  • 302 Found - 临时重定向->location
  • 304 Not Modified - 资源未修改,直接使用缓存
  1. 400系列 - 客户端错误,表示请求存在语法错误或无法完成请求。常见有:
  • 400 Bad Request - 请求报文存在语法错误
  • 401 Unauthorized - 需要身份认证信息
  • 403 Forbidden - 服务器拒绝请求
  • 404 Not Found - 请求资源不存在
  1. 500系列 - 服务器内部错误,表示服务器无法完成请求。常见有:
  • 500 Internal Server Error - 服务器内部错误
  • 503 Service Unavailable - 服务器暂时过载或维护

简单的反爬操作:

请求头:

  • User-Agent:标识客户端浏览器信息,可用于反爬检测,表示用户用什么设备发送的请求。

    • 直接从浏览器复制,用于伪装访问设备。
  • Cookie:网站用于跟踪会话,可检测非正常Cookie来实现反爬,是服务器记录在浏览器上的一个字符串,写入在本地的一个文件中,作用是和服务器保持住会话,在服务器端叫session。(HTTP请求是无状态请求)

      1. 从浏览器直接复制,适用于简单场景。
      1. 使用requests.session()自动保持会话,处理set-cookie,适用于复杂场景。如果网页使用Js维护Cookie,需要自己额外处理。
  • Referer:标识来源页面,用来检测上一个url是什么,可检测Referer来防止盗链。

    • 直接复制来源页面URL,用于伪造访问来源。
  • 网页自定义参数:这是最难处理的,需要通过逆向工程分析参数算法,找到生成参数的代码逻辑。

响应头:

  • Location:302重定向地址,可设置跳转难以解析的页面用于反爬。
  • Set-Cookie:设置Cookie,可用于保存难以伪造的Cookie实现访问控制。
  • 网站还可以在这些头部中添加各种参数,来进行访问验证、opensession遥测等,以识别爬虫行为。

requests.Session的用法:

创建Session对象

import requestssession = requests.Session()

首先导入requests模块,然后调用requests.Session()来创建一个Session对象。

设置请求头

可以通过Session对象的headers属性预设请求头,这些头信息将会应用于该Session实例发出的所有请求:

session.headers = {'User-Agent': 'Mozilla/5.0','Authorization': 'Bearer xxxxxxxxxxxxx' 
}

设置Cookies

session.cookies.update({'name': 'value','foo': 'bar'
})

通过Session的cookies属性可以预设请求中的Cookies。

发送请求

response = session.get(url, params=params)
response = session.post(url, data=data) 

可以使用Session对象的get()、post()等方法发送请求。

关闭Session

session.close()

当Session使用完后,可以调用close()方法关闭该Session对象。
相比直接使用requests.get()/post()等函数,使用Session对象的好处是:

  • 避免重复传参,提高效率
  • 自动处理Cookies,实现状态保持
  • 方便REQUESTS头及Cookies的管理

数据解析方法

三种解析HTML数据的方法:

  1. 正则表达式re
  • 在html中获取到js的一部分代码(字符串)
  • 使用re.compile()编译正则表达式
  • re.findall()方法根据正则在文本中提取匹配内容
  • 适用于从文本中提取固定模式的字符串
import rehtml = '<script>var data = "abc"</script>'pattern = re.compile(r'var data = "(.*)"') 
result = pattern.findall(html)
  1. 调用xpath()提取指定节点
  • 用来解析常规的html结构.
  • 可以获取属性、文本等信息
  • 处理速度快
from lxml import etreehtml = etree.HTML(resp.text)
result = html.xpath('//li/text()')

etree的xpath默认返回的是列表.

if ret:ret[0]
else:XXX
  1. BeautifulSoup
  • 创建BeautifulSoup对象解析.xml,.svg
  • 使用find()/find_all()搜索文档树
  • 获取name、attrs、text等信息
  • 可以处理不规整文档
from bs4 import BeautifulSoupsoup = BeautifulSoup(html, 'lxml')
result = soup.find_all('li')

综合来说,正则适合提取固定模式字符串,lxml解析速度快,BeautifulSoup可以应对“烂”文档。

json和jsonp的解析方法:

  1. JSON数据解析
  • 从响应中获取JSON字符串
resp_text = response.text
  • 尝试直接加载解析
try:data = response.json() 
except:# 处理异常
  • 如果失败,则手动加载解析
import jsondata = json.loads(resp_text )
  • 在解析前,一定要打印检查resp_text 确认是标准JSON格式,才进行解析。
  • 如果遇到反爬.你很可能拿到的东西和抓包工具不一致.
  • 切记,先打印resp_text .确定好你的返回的内容是json格式,才开始转化
  1. JSONP数据解析
  • JSONP格式如:XXXXXX({json}) => {json}
  • 想办法去掉左右两端的XXXXXX( )=>得到的就是json
  • “XXXXXX({json}) “.replace(“XXXXXX(”,””)[:-1]
  • 需要去除方法调用部分,保留JSON字符串
  • 得到JSON字符串后,加载解析
    在这里插入图片描述
    在这里插入图片描述
    以上两张图可以看出XXXXXX为callback值

多任务异步爬虫.多线程,多进程,协程异步I/O

  1. 区别
  • 多线程:线程之间共享进程内存空间,线程切换成本低,适合I/O密集作业。但线程不安全,需要锁机制。
  • 多进程:进程有独立内存, Kosten比线程高,适合CPU密集作业。进程间通信复杂,需要IPC。
  • 协程:在单线程中以异步方式实现并发,减少切换带来的消耗。适合I/O密集场景,可大幅提升效率。
  1. 适用场景
  • 多线程:爬取大量小页面,线程间共享解析函数等。
  • 多进程:爬取数据规模巨大,CPU密集型数据处理。
  • 协程:需要大量I/O操作的异步爬虫,提高并发量。
  1. 实现难度
  • 多线程:线程模块较为简单,难点在线程安全和死锁问题。
  • 多进程:进程间通信和数据传递实现复杂度高。
  • 协程:需理解异步语法,错误调试难度较大。

多线程

  • 原理:导入threading模块,用Thread类创建线程。线程间共享进程内存空间,互不影响,可同时执行。
  • 实例:
from threading import Thread
import requestsdef crawl(url):r = requests.get(url)print(r.text)t1 = Thread(target=crawl, args=('url1',))
t2 = Thread(target=crawl, args=('url2',))
t1.start()
t2.start()

多进程

  • 原理:导入multiprocessing模块,用Process类创建进程。进程有独立内存空间,需要通过Queue、Pipe等方式通信。
  • 实例:
from multiprocessing import Process, Queuedef crawler(q):data = crawl_page() q.put(data)q = Queue()
p1 = Process(target=crawler, args=(q,))
p2 = Process(target=crawler, args=(q,))
p1.start() 
p2.start()

协程异步I/O

  • 原理:使用async/await语法,进行异步编程。遇await切换到其他协程,不阻塞程序执行。
  • 实例:
import asyncioasync def fetch(url):print('fetching')return await aiohttp.get(url)async def main():await fetch(url1)await fetch(url2)loop = asyncio.get_event_loop()
loop.run_until_complete(main())

数据存储

CSV

  • CSV适合存储表格化数据,如电商订单、用户信息等
  • 可以用Excel等软件方便编辑和查看数据
  • 支持数据交换,可以导入到数据库或其他系统
  • Python中常用csv模块操作
import csv# 写入CSV文件
with open('data.csv', 'w', newline='') as csvfile:writer = csv.writer(csvfile)# 写入标题行  writer.writerow(['ID', 'Name', 'Age'])  # 写入数据行writer.writerow(['1', '张三', 20])writer.writerow(['2', '李四', 25])# 读取CSV文件    
with open('data.csv', 'r') as csvfile:reader = csv.reader(csvfile)# 读取标题    headers = next(reader)  # 读取每行数据for row in reader:print(row)
  • 字典写入CSV
import csvwith open('data.csv', 'w', newline='') as f:fieldnames = ['id', 'name', 'age']writer = csv.DictWriter(f, fieldnames=fieldnames)writer.writeheader()writer.writerow({'id': 1, 'name': '张三', 'age': 20})writer.writerow({'id': 2, 'name': '李四', 'age': 25})
  • Pandas读写CSV并存入Excel
import pandas as pddf = pd.read_csv('data.csv')
df.to_csv('new_data.csv', index=False)
df.to_excel( "hehe.xls", header=False,index=False)

csv本质是文本文件

f = open("data.csv", modew" , encoding="utf-8")f.write("1")
f.write(" , ")
f.write("张三")
f.write(" , ")
f.write( '"张,三"')
f.write(" , ")
f.write("5000")
f.write(" \n ")
f.write(" , ")
f.write("张四")
f.write(" , ")
f.write( '"张,四"')
f.write(" , ")
f.write("5030")
f.write(" \n ")
import pandas
r = pandas.read_csv ( "data.csv " , sep="," , headen=None)
print(r)
r.to_excel( "hehe.xls", header=False,index=False)

MySQL

  • 数据类型:整型、字符串、日期时间等,设置符合存储需求的字段类型
  • 查询语句:SELECT与WHERE过滤数据,ORDER BY排序,LIMIT分页
  • 联表查询:INNER JOIN,LEFT/RIGHT JOIN 等方式联结多个表GetData
  • 事务处理:START TRANSACTION到COMMIT,处理包含多条SQL语句的事务
  • Python中操作:
import pymysql# 连接数据库
conn = pymysql.connect(host='localhost', user='root', passwd='123456', db='test')# 插入数据
cursor = conn.cursor()
cursor.execute("INSERT INTO tb_user VALUES (NULL, '张三', 25)") 
conn.commit()# 查询数据
cursor.execute("SELECT * FROM tb_user")
result = cursor.fetchall()
print(result)

MongoDB

  • 文档存储:JSON格式灵活存储数据
  • 数据模式自由,无需定义表结构
  • 丰富的查询语言:正则匹配、树形查询、地理位置查询等
  • Python中操作:
from pymongo import MongoClient# 连接Mongodb
client = MongoClient('localhost', 27017)
collection = client['testdb']['user']# 插入文档
data = {'name': '张三', 'age': 25}
collection.insert_one(data)# 查询文档  
results = collection.find({'age': {'$gt': 20}}) 
for result in results:print(result)

Redis

  • 键值对存储,value支持多种数据结构
  • 提供字符串、哈希、列表、集合、有序集合5种数据结构操作
  • 支持事务,具有原子性
  • 丰富的功能:发布订阅、LRU过期等
  • Python中操作:
import redis# 连接Redis
r = redis.StrictRedis(host='localhost', port=6379, db=0)# 字符串操作
r.set('username', '张三') # 散列操作
r.hset('user', 'name', '张三')  # 列表操作
r.lpush('list', 1,2,3)

面向对象编程

编程思想的转变

目前我们编写的代码属于面向过程:

  1. 获取页面源代码
  2. 解析页面源代码
  3. 存储数据

面向过程注重步骤,按照顺序一步步实现功能。
类似我要喝可乐的过程:

  1. 从沙发上起来
  2. 走到冰箱门前
  3. 拿出可乐
  4. 喝一口
  5. 关上冰箱门

面向对象思维

面向对象编程核心在于思维方式的转变:

  • 你要操纵对象,让对象给你干活
  • 最终结果都是能喝到可乐
  • 让对象去操作

要实现面向对象需要:

  1. 定义对象
  2. 让对象会进行操作

程序员可以自由构思创造对象,然后定义对象的属性和方法。

创建对象

在Python中通过类(Class)可以创建对象,类是对象的模板,包含对象的属性和方法。
定义一个类:

class Cat:def __init__(self, name, age):self.name = nameself.age = agedef meow(self):print("喵喵喵")tom = Cat("汤姆", 3)
tom.meow()

面向对象编程可以提高代码的封装性、继承性和可维护性。需要转换编程思维方式,主要关注对象和类的设计。

总结

本文全面介绍了网页加载、数据处理和存储的关键概念和技术。无论是初学者还是有一定经验的开发者,都能从中受益匪浅。通过掌握这些技能,读者可以更有效地收集和处理网络数据,为各种应用场景提供有力支持。无论是进行数据分析、信息收集、还是网站开发,本文提供了重要的基础知识和实用技巧。希望读者能够积极学习和实践,不断提升自己的技能水平。

特别声明:
此教程为纯技术分享!本教程的目的决不是为那些怀有不良动机的人提供及技术支持!也不承担因为技术被滥用所产生的连带责任!本教程的目的记录分享学习技术的过程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/82802.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

(手撕)数据结构--->堆

文章内容 目录 一&#xff1a;堆的相关概念与结构 二&#xff1a;堆的代码实现与重要接口代码讲解 让我们一起来学习:一种特殊的数据结构吧&#xff01;&#xff01;&#xff01;&#xff01; 一&#xff1a;堆的相关概念与结构 在前面我们已经简单的学习过了二叉树的链式存储结…

Linux Day17 生产者消费者

一、生产者消费者问题概述 生产者 / 消费者问题&#xff0c;也被称作有限缓冲问题。两个或者更多的线程共享同一个缓冲 区&#xff0c;其中一个或多个线程作为 “ 生产者 ” 会不断地向缓冲区中添加数据&#xff0c;另一个或者多个线程作为 “ 消费者 ” 从缓冲区中取走数据。…

【MySQL系列】- MySQL自动备份详解

【MySQL系列】- MySQL自动备份详解 文章目录 【MySQL系列】- MySQL自动备份详解一、需求背景二、Windows mysql自动备份方法2.1 复制date文件夹备份实验备份环境创建bat直接备份脚本 2 .2 mysqldump备份成sql文件创建mysqldump备份脚本 2 .3 利用WinRAR对MySQL数据库进行定时备…

【每日一题】154. 寻找旋转排序数组中的最小值 II

154. 寻找旋转排序数组中的最小值 II - 力扣&#xff08;LeetCode&#xff09; 已知一个长度为 n 的数组&#xff0c;预先按照升序排列&#xff0c;经由 1 到 n 次 旋转 后&#xff0c;得到输入数组。例如&#xff0c;原数组 nums [0,1,4,4,5,6,7] 在变化后可能得到&#xff1…

基于SSM的智慧城市实验室主页系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

linux学习实操计划0103-安装软件

本系列内容全部给基于Ubuntu操作系统。 系统版本&#xff1a;#32~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Fri Aug 18 10:40:13 UTC 1 安装deb格式软件 Debian包是Unixar的标准归档&#xff0c;将包文件信息以及包内容&#xff0c;经过gzip和tar打包而成。 处理这些包的经典程序是…

git基本手册

Git and GitHub for Beginners Tutorial - YouTube Kevin Stratvert git config --global user.name “xxx” git config --global user.email xxxxx.com 设置默认分支 git config --global init.default branch main git config -h查看帮助 详细帮助 git help config 清除 cl…

vue国际化教程

需求背景 项目需求要做国际化&#xff0c;结果网上找了好几篇文章&#xff0c;没有一个可以一次性搞定&#xff0c;现在这里总结一下。首先&#xff0c;我们分为两部分处理&#xff0c;一个是前端页面的静态文字&#xff0c;这个由前端vue.json自行处理。第二部分就是后端的错…

《计算机视觉中的多视图几何》笔记(5)

5 Algorithm Evaluation and Error Analysis 本章主要讲述对算法的验证和误差分析。 概述了两种计算这种不确定性&#xff08;协方差&#xff09;的方法。第一个基于线性近似值&#xff0c;涉及串联各种雅各布表达式&#xff0c;第二个是更容易实施蒙特卡洛方法。 文章目录 …

Pytorch面试题整理(2023.09.10)

1、pytorch如何微调fine tuning&#xff1f; 在加载了预训练模型参数之后&#xff0c;需要finetuning 模型&#xff0c;可以使用不同方式finetune。 局部微调&#xff1a;加载了模型参数后&#xff0c;只想调节最后几层&#xff0c;其他层不训练&#xff0c;也就是不进行梯度…

从命令行管理文件(二)

1.数据流和重定向 1.2数据流 标准输入 (standard input&#xff0c;简称stdin):默认情况下&#xff0c;标准输入指从键盘获取的输入 标准输出(standard output&#xff0c;简称stdout): 默认情况下&#xff0c;命令执行所回传正确的信息会输出到屏幕上 标准错误输出(standard …

Ui自动化测试上传文件方法都在这里了

前言 实施UI自动化测试的时候&#xff0c;经常会遇见上传文件的操作&#xff0c;那么对于上传文件你知道几种方法呢&#xff1f;今天我们就总结一下几种常用的上传文件的方法&#xff0c;并分析一下每个方法的优点和缺点以及哪种方法效率&#xff0c;稳定性更高 被测HTML代码…

【计算机基础】Git系列2:配置多个SSH

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…

大数据课程L7——网站流量项目的操作步骤

文章作者邮箱&#xff1a;yugongshiyesina.cn 地址&#xff1a;广东惠州 ▲ 本章节目的 ⚪ 了解网站流量项目的Spark与HBase整合&#xff1b; ⚪ 掌握网站流量项目的实时流业务处理&#xff1b; 一、 Spark 与 HBase 整合基础 1. 实现步骤&#xff1a; 1. 启动…

各个国家商品条形码

什么是商品条码&#xff1f; 我们常说的条形码其实就是商品条码&#xff0c;它是由一组规则排列的条、空及其对应代码组成&#xff0c;表示商品代码的条码符号&#xff0c;主要用于零售商品、储运包装商品、物流单元、参与方位置等的代码与条码标识。通俗来讲&#xff0c;商品…

Antmonsido(AMS)早期预售(IDO)如何参与?

Antmonsido是Kucoin两年前开始孵化的项目&#xff0c;第一款全链游戏已经开发完成&#xff0c;项目的NFT已经上过币安&#xff0c;前两周刚完成180万美元融资&#xff0c;投资机构也都很强势&#xff0c;IDO注册人数超过三万&#xff0c;海外热度超高&#xff0c;19号上GATE&am…

Java Semaphore使用例子和流程

目录 Semaphore例子代码和输出semaphore.acquire();semaphore.release(); Semaphore semaphore : 英[ˈseməfɔː(r)] 美[ˈseməfɔːr] n. 旗语; 信号标; v. 打旗语; (用其他类似的信号系统)发信号; [例句]Semaphore was widely used at sea, before the advent of electr…

交换机上的PoE技术

交换机的PoE代表Power over Ethernet&#xff08;以太网供电&#xff09;&#xff0c;它是一种技术&#xff0c;允许通过以太网电缆传输数据的同时为连接的设备提供电力供应。 传统上&#xff0c;网络设备&#xff08;如IP电话、无线接入点、网络摄像机等&#xff09;通常需要…

stu01-IDEA怎么创建一个HTML项目

1.打开idea&#xff0c;依次点击file→new→project 2.点击Java&#xff0c;选择你的jdk&#xff0c;没有下载的点击“Download JDK”/已经下载有JDK但在这里没显示的→点击“Add JDK”&#xff0c;选择你安装的JDK的路径&#xff0c;然后next 3.next 4.起好名字&#xff0c;我…

每日一题~二叉树的最近公共祖先

题目连接&#xff1a;236. 二叉树的最近公共祖先 - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 思路分析&#xff1a; 由题可知&#xff0c;我们需要找到 p 和 q 两个二叉树的最近公共祖先节点&#xff0c;首先我们分析一下&#xff0c;这个最近公共祖先节点…