Python方面
有时候会忘记,要查一下字典,相对于HTML的CSS来说基本没问题。
下面有几个注意点:
requests
前言
此物用之简易,勿多言,其中道理可自源码观其注释而得(码字太多有点累)
快速入手
*(建议搭配JSON食用口味更佳)*
requests
的开始,是从 requests.post
的,其中,有三常用项
参数名 | 解释 | 示例 |
---|---|---|
url | 网站URL | https://www.baidu.com/ |
param | 查询参数 | JSON格式数据 |
data | 正文参数 | JSON格式数据 |
headers | 请求标头 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0" |
注意!get请求没有主体,所以data参数无效,post有,所以post可以用param与data
当访问频率较高时,可能出现对于UA(请求头中)或者对于IP的禁止访问
-
UA封禁
:可以尝试构建headers_list
用random.choice()
随机选择每次的UA,减少封禁可能性。 -
IP封禁
:用代理服务器
如果等不及下载,不知道是不是卡了的情况下,可以使用 tqdm
库显示进度条
大概说一下多线程和多进程
线程进程优化
线程池(Pool
)
首先,我们需要
from multiprocessing import Pool
然后使用 Pool(num: int)
创建一个线程池
注意:num
的大小为线程池线程的数量,如果创建的线程小于需要的线程,多出的线程会等待正在运行的线程被释放后载入运行
Pool
可以被赋值给其他变量,如
pool = Pool(4)
也允许用 with
直接封装,如
with Pool(4) as pool:
线程池常用函数
函数名 | 功能描述 |
---|---|
apply | 同步地执行给定的函数并返回结果,相当于单个进程执行。 |
apply_async | 异步地执行给定的函数,立即返回一个 AsyncResult 对象,可以用于获取结果或等待任务完成。 |
map | 同步地并发执行给定的函数,作用于一个可迭代对象的每个元素,并返回一个包含所有结果的列表。 |
map_async | 异步地并发执行给定的函数,作用于一个可迭代对象的每个元素,立即返回一个 AsyncResult 对象。 |
starmap | 同步地并发执行给定的函数,作用于一个可迭代对象的每个元素,参数必须是带有多个参数的序列(如元组),并返回一个包含所有结果的列表。 |
starmap_async | 异步地并发执行给定的函数,作用于一个可迭代对象的每个元素,参数必须是带有多个参数的序列(如元组),立即返回一个 AsyncResult 对象。 |
close | 关闭进程池,不再接受新的任务。需要在 join 之前调用。 |
terminate | 立即终止进程池中的所有进程,不再处理未完成的任务。 |
join | 等待所有进程池中的工作进程完成。必须在 close 或 terminate 之后调用。 |
imap | 返回一个迭代器,它按顺序获取给定函数应用于可迭代对象每个元素后的结果,逐个生成结果并保持处理顺序。 |
imap_unordered | 返回一个迭代器,它获取给定函数应用于可迭代对象每个元素后的结果,结果顺序是不确定的(即异步生成结果)。 |
get | 获取 apply_async 、map_async 、starmap_async 返回的 AsyncResult 对象的结果(阻塞直到任务完成)。 |
ready | 检查 AsyncResult 是否已经完成并可用。 |
wait | 等待 AsyncResult 对象的任务完成,可以选择设置超时时间。 |
successful | 检查 AsyncResult 对象的任务是否成功完成。 |
常用函数简介
- 同步 vs 异步:
- 同步方法(
apply
、map
、starmap
)会阻塞主进程,直到所有任务完成。 - 异步方法(
apply_async
、map_async
、starmap_async
)不会阻塞主进程,立即返回AsyncResult
对象,可以通过get
方法获取结果。
- 同步方法(
map
系列:map
和map_async
作用于单个参数的函数和可迭代对象。starmap
和starmap_async
作用于带有多个参数的函数,每个参数的组合必须打包成元组或列表。
- 结果处理:
imap
和imap_unordered
返回迭代器,可以逐步处理结果。imap
保持原始顺序,而imap_unordered
则不保证顺序。
- 进程管理:
close
、terminate
和join
用于管理进程池的生命周期。close
和terminate
停止进程池接受新任务,join
等待所有任务完成。
异步与非异步示例
使用 Pool.apply
和 Pool.apply_async
(AI)
from multiprocessing import Pool
import time
def square(x):
print(f"Computing square of {x}")
time.sleep(2) # 模拟一个耗时操作
return x * x
if __name__ == "__main__":
with Pool(4) as pool:
# 使用 apply 同步方法
print("Using apply...")
result = pool.apply(square, (5,))
print("Result from apply:", result)
# 使用 apply_async 异步方法
print("\nUsing apply_async...")
result_async = pool.apply_async(square, (10,))
print("Doing some other work in the main process...")
# 获取异步调用的结果
result = result_async.get()
print("Result from apply_async:", result)
使用 Pool.map
和 Pool.map_async
(AI)
from multiprocessing import Pool
import time
def square(x):
time.sleep(1)
return x * x
if __name__ == "__main__":
numbers = [1, 2, 3, 4, 5]
with Pool(4) as pool:
# 使用 map 同步方法
results = pool.map(square, numbers)
print("map 结果:", results)
# 使用 map_async 异步方法
async_result = pool.map_async(square, numbers)
print("map_async 结果:", async_result.get())
使用 Pool.starmap
和 Pool.starmap_async
(AI)
from multiprocessing import Pool
import time
def multiply(x, y):
print(f"Multiplying {x} and {y}")
time.sleep(2) # 模拟一个耗时操作
return x * y
if __name__ == "__main__":
with Pool(4) as pool:
# 使用 starmap 同步方法
print("Using starmap...")
result = pool.starmap(multiply, [(1, 2), (3, 4), (5, 6)])
print("Result from starmap:", result)
# 使用 starmap_async 异步方法
print("\nUsing starmap_async...")
result_async = pool.starmap_async(multiply, [(7, 8), (9, 10), (11, 12)])
print("Doing some other work in the main process...")
# 获取异步调用的结果
result = result_async.get()
print("Result from starmap_async:", result)
其他的不再演示,有兴趣请自行查询
协程(asyncio
)
是干货,建议好好睡一觉精力充沛了再理解
常用函数
函数名 | 功能描述 |
---|---|
asyncio.run(coro) | 运行一个协程,自动管理事件循环的生命周期,直到协程完成。 |
asyncio.create_task(coro) | 创建一个任务(Task)来并发运行协程,立即返回 Task 对象,任务会被安排在事件循环的下一个时间片执行。 |
asyncio.sleep(seconds) | 异步地暂停执行一段时间,不会阻塞事件循环,常用于模拟 I/O 操作。 |
asyncio.gather(*coros) | 并行执行多个协程并收集它们的结果,返回一个包含所有协程结果的列表。 |
asyncio.wait(tasks) | 等待多个任务(Task)完成,可设置超时时间和完成条件。 |
asyncio.as_completed(coros) | 创建一个迭代器,当协程完成时按完成顺序返回结果。 |
asyncio.Event() | 创建一个事件对象,用于协程之间的同步操作。 |
asyncio.Queue() | 创建一个异步队列,用于协程之间的通信。 |
asyncio.Lock() | 创建一个异步锁,用于协程之间的同步操作。 |
asyncio.Semaphore() | 创建一个信号量对象,用于限制并发量。 |
asyncio.get_event_loop() | 获取当前线程的事件循环。 |
asyncio.run_until_complete(future) | 运行直到 future 完成,通常在事件循环中使用。 |
简单示例
import asyncio
async def async_task1():
print("Task 1: Starting")
await asyncio.sleep(2)
print("Task 1: Completed")
return "Result from Task 1"
async def async_task2():
print("Task 2: Starting")
await asyncio.sleep(1)
print("Task 2: Completed")
return "Result from Task 2"
async def main():
print("Starting main function")
# 创建两个任务,并发运行两个协程
task1 = asyncio.create_task(async_task1())
task2 = asyncio.create_task(async_task2())
# 等待任务完成并获取结果
results = await asyncio.gather(task1, task2)
print("Results:", results)
print("Main function completed")
# 使用 asyncio.run() 启动事件循环并运行 main 协程
asyncio.run(main())
拓展示例
asyncio.as_completed(coros)
示例(AI生成的示例)
特点比较:
asyncio.as_completed
:
- 适合需要按任务完成顺序处理结果的情况。特别是在你关心任务完成的时间顺序时,例如处理任务流或实时反馈。
asyncio.gather
:
- 适合需要等待所有任务完成并按给定顺序返回结果的情况。适用于所有任务完成后一起处理结果的场景。
import asyncio
import random
async def async_task(task_id):
# 模拟一个耗时的异步操作,时间为 1 到 5 秒之间的随机数
delay = random.randint(1, 5)
print(f"Task {task_id}: Starting with delay {delay} seconds")
await asyncio.sleep(delay)
print(f"Task {task_id}: Completed after {delay} seconds")
return f"Result from Task {task_id}"
async def main():
print("Starting main function")
# 创建多个协程任务
tasks = [async_task(i) for i in range(5)]
# 使用 asyncio.as_completed 来处理按完成顺序的任务
for completed_task in asyncio.as_completed(tasks):
result = await completed_task
print(f"Received: {result}")
print("Main function completed")
# 使用 asyncio.run() 启动事件循环并运行 main 协程
asyncio.run(main())
输出:
Starting main function
Task 0: Starting with delay 3 seconds
Task 1: Starting with delay 1 seconds
Task 2: Starting with delay 4 seconds
Task 3: Starting with delay 2 seconds
Task 4: Starting with delay 5 seconds
Task 1: Completed after 1 seconds
Received: Result from Task 1
Task 3: Completed after 2 seconds
Received: Result from Task 3
Task 0: Completed after 3 seconds
Received: Result from Task 0
Task 2: Completed after 4 seconds
Received: Result from Task 2
Task 4: Completed after 5 seconds
Received: Result from Task 4
Main function completed
包含 asyncio.Event
、asyncio.Queue
、asyncio.Lock
和 asyncio.Semaphore
的示例(AI)
import asyncio
# 全局队列,用于在任务之间传递数据
queue = asyncio.Queue()
# 全局事件,用于协调任务
event = asyncio.Event()
# 全局锁,用于控制对共享资源的访问
lock = asyncio.Lock()
# 全局信号量,用于限制并发量
semaphore = asyncio.Semaphore(2) # 允许最多两个任务同时执行
async def producer():
print("Producer: Starting")
for i in range(5):
await asyncio.sleep(1) # 模拟生产过程
item = f"item_{i}"
await queue.put(item)
print(f"Producer: Produced {item}")
event.set() # 通知消费者生产已完成
print("Producer: Finished")
async def consumer(name):
print(f"Consumer {name}: Waiting for items")
await event.wait() # 等待生产者完成生产
while not queue.empty():
async with semaphore:
async with lock:
if queue.empty():
break # 退出循环当队列为空
item = await queue.get()
print(f"Consumer {name}: Consumed {item}")
await asyncio.sleep(2) # 模拟消费过程
queue.task_done()
print(f"Consumer {name}: Finished")
async def main():
# 启动生产者和消费者
prod = asyncio.create_task(producer())
cons1 = asyncio.create_task(consumer("A"))
cons2 = asyncio.create_task(consumer("B"))
# 等待生产者和消费者完成
await asyncio.gather(prod, cons1, cons2)
# 运行主程序
asyncio.run(main())
示例解释
asyncio.Queue
:- 用于在生产者和消费者之间传递数据。生产者将数据放入队列中,消费者从队列中取出数据。
- 在
producer
协程中,生产者将数据项放入队列中。 - 在
consumer
协程中,消费者从队列中获取数据项。
asyncio.Event
:- 用于协调任务,通知消费者生产已经完成。
- 生产者在完成生产后调用
event.set()
,通知所有等待事件的消费者可以开始消费。
asyncio.Lock
:- 用于控制对共享资源(队列)的访问,确保同一时间只有一个消费者能从队列中取出数据。
- 在消费者中使用
async with lock
以确保对队列的访问是线程安全的。
asyncio.Semaphore
:- 用于限制并发任务的数量。信号量的计数器设置为 2,表示最多允许两个消费者同时执行。
- 在消费者中使用
async with semaphore
限制并发数量。
对于协程的理解
协程的执行和调度
在 asyncio
中,协程的执行和调度是通过事件循环管理的。以下是协程调度和交替执行的关键点:
- 事件循环管理协程:
- 事件循环负责管理和调度协程的执行。协程可以挂起(例如等待 I/O 操作或使用
await
),在挂起期间,事件循环会调度其他协程运行。
- 事件循环负责管理和调度协程的执行。协程可以挂起(例如等待 I/O 操作或使用
- 协程的挂起和恢复:
- 当一个协程在执行
await
或等待 I/O 操作时,它会被挂起,事件循环会暂停它的执行,转而执行其他准备好的协程。 - 一旦等待的操作完成,事件循环会恢复挂起的协程,并继续执行它的剩余部分。
- 当一个协程在执行
- 信号量和锁的作用:
- 使用
asyncio.Semaphore
可以限制同时运行的协程数量,控制并发的程度。例如,信号量限制在同一时间只能有两个协程进入其关键部分。 asyncio.Lock
用于确保同一时间只有一个协程可以访问共享资源。
- 使用
代码块和交替执行
在你的代码示例中,当一个协程进入 async with semaphore
代码块时:
- 信号量控制:
- 如果信号量允许,协程会进入代码块并执行。信号量的计数器会减少。如果信号量计数器为零,其他协程将被阻塞,直到有协程释放信号量。
- 交替执行:
- 在协程中使用
await
或进行异步操作时,事件循环会切换到其他准备好的协程。这个过程是交替进行的,但不一定是交替进行的顺序。事件循环会根据协程的状态和事件调度它们。 - 当协程在
async with semaphore
代码块中等待(例如await queue.get()
),它会被挂起,事件循环会调度其他协程执行。
- 在协程中使用
threading
捏~
没学也说说吧(也比较干)
常用函数
函数/类 | 描述 |
---|---|
threading.Thread | 用于创建和管理线程。使用 target 参数指定线程运行的函数。 |
threading.Lock | 用于线程间的互斥锁,确保同一时间只有一个线程可以访问共享资源。 |
threading.RLock | 可重入锁,允许一个线程多次获取锁。 |
threading.Semaphore | 信号量,用于控制同时运行的线程数量。 |
threading.Event | 事件对象,用于线程间的通信和同步。 |
threading.Condition | 条件变量,用于在特定条件下线程的等待和通知。 |
threading.Barrier | 用于线程同步的屏障,等待多个线程到达某个点后才继续执行。 |
threading.Timer | 用于定时任务,创建一个在指定时间后运行的线程。 |
简单示例
import threading
import time
# 定义线程执行的函数
def print_numbers():
for i in range(5):
print(i)
time.sleep(1)
# 创建线程
thread = threading.Thread(target=print_numbers)
# 启动线程
thread.start()
# 等待线程完成
thread.join()
print("Thread finished")
拓展示例
函数示例(AI)
import threading
import time
# 全局变量,用于演示锁和信号量的使用
shared_resource = 0
lock = threading.Lock() # 互斥锁,确保同一时间只有一个线程可以访问共享资源
semaphore = threading.Semaphore(2) # 信号量,限制同时进入的线程数量
# 使用 RLock 示例
rlock = threading.RLock() # 可重入锁,允许线程多次获取锁
# 使用 Condition 示例
condition = threading.Condition() # 条件变量,用于线程之间的通知和等待
# 使用 Barrier 示例
barrier = threading.Barrier(3) # 屏障,等待多个线程到达某个点
# 线程执行的工作函数
def thread_worker(name):
global shared_resource
# 使用信号量控制并发访问
with semaphore:
print(f"Thread {name} has acquired semaphore")
time.sleep(1) # 模拟线程操作
# 使用锁保护共享资源访问
with lock:
global shared_resource
shared_resource += 1
print(f"Thread {name} updated shared_resource to {shared_resource}")
# 使用可重入锁
with rlock:
print(f"Thread {name} has acquired rlock")
time.sleep(1) # 模拟锁的可重入操作
# 使用条件变量
with condition:
print(f"Thread {name} waiting on condition")
condition.wait(timeout=2) # 等待条件变量通知
print(f"Thread {name} resumed after condition")
print(f"Thread {name} finished")
def barrier_worker(name):
print(f"Barrier worker {name} starting")
time.sleep(1) # 模拟工作
print(f"Barrier worker {name} is waiting at the barrier")
barrier.wait() # 等待其他线程到达屏障
print(f"Barrier worker {name} passed the barrier")
def condition_notifier():
time.sleep(2) # 等待一段时间以确保其他线程已经在等待条件变量
with condition:
print("Condition notifier notifying")
condition.notify_all() # 通知所有等待的线程
def main():
# 启动线程池
threads = []
for i in range(3):
thread = threading.Thread(target=thread_worker, args=(f"Worker-{i}",))
threads.append(thread)
thread.start()
# 启动条件变量通知线程
notifier = threading.Thread(target=condition_notifier)
notifier.start()
# 启动屏障线程
barrier_threads = []
for i in range(3):
barrier_thread = threading.Thread(target=barrier_worker, args=(f"Barrier-{i}",))
barrier_threads.append(barrier_thread)
barrier_thread.start()
# 等待所有线程完成
for thread in threads:
thread.join()
# 等待条件变量通知线程完成
notifier.join()
# 等待所有屏障线程完成
for barrier_thread in barrier_threads:
barrier_thread.join()
print(f"Final shared_resource value: {shared_resource}")
# 运行主程序
if __name__ == "__main__":
main()
说明
- 全局变量和同步机制:
shared_resource
: 用于演示线程对共享资源的访问。lock
: 互斥锁,确保对shared_resource
的访问是线程安全的。semaphore
: 信号量,限制同时进入某个代码块的线程数量。rlock
: 可重入锁,允许线程在持有锁时再次获得它。condition
: 条件变量,用于线程间的等待和通知。barrier
: 屏障,用于等待多个线程到达某个同步点。
- 线程工作函数 (
thread_worker
):- 使用信号量控制并发。
- 使用锁保护对
shared_resource
的访问。 - 使用可重入锁,演示可重入锁的特性。
- 使用条件变量,等待通知并在收到通知后恢复执行。
- 屏障线程函数 (
barrier_worker
):- 每个线程模拟工作后,等待其他线程到达屏障。所有线程到达后,屏障会解除,线程继续执行。
- 条件变量通知函数 (
condition_notifier
):- 在等待了一段时间后,通知所有在条件变量上等待的线程。
- 主函数 (
main
):- 启动线程池,每个线程执行
thread_worker
函数。 - 启动一个条件变量通知线程,用于通知等待条件变量的线程。
- 启动屏障线程,每个线程执行
barrier_worker
函数。 - 等待所有线程完成,包括条件变量通知线程和屏障线程。
- 启动线程池,每个线程执行
- 运行主程序:
- 使用
main()
函数启动所有线程和操作。
- 使用
关键点总结
- 线程控制: 使用
threading.Thread
创建和管理线程。 - 同步机制: 使用
threading.Lock
、threading.Semaphore
、threading.RLock
、threading.Condition
和threading.Barrier
等同步工具来控制并发和资源访问。 - 条件变量和屏障: 使用条件变量和屏障来实现线程间的通知和同步。
写的不错,下次继续用(乐)
asyncio
与 threading
的综合运用(AI)
import threading
import asyncio
import time
# 定义一个共享资源和一个锁
shared_resource = 0
lock = threading.Lock() # 线程锁,用于控制对共享资源的访问
# 定义一个信号量,允许最多两个线程同时访问共享资源
semaphore = threading.Semaphore(2)
# 异步任务:模拟异步操作
async def async_task(name):
print(f"Async task {name} starting")
await asyncio.sleep(2) # 模拟异步操作
print(f"Async task {name} finished")
# 使用线程的工作函数
def thread_worker(name):
global shared_resource
print(f"Thread {name} starting")
# 使用信号量控制并发
with semaphore:
print(f"Thread {name} has acquired semaphore")
time.sleep(1) # 模拟线程操作
with lock: # 使用锁保护对共享资源的访问
shared_resource += 1
print(f"Thread {name} updated shared_resource to {shared_resource}")
print(f"Thread {name} finished")
# 在线程中运行的函数
def run_asyncio_loop(loop):
asyncio.set_event_loop(loop)
# 运行两个异步任务
loop.run_until_complete(asyncio.gather(
async_task("A"),
async_task("B")
))
async def main():
# 创建并启动线程
threads = []
for i in range(3):
thread = threading.Thread(target=thread_worker, args=(f"Worker-{i}",))
threads.append(thread)
thread.start()
# 创建新的事件循环
new_loop = asyncio.new_event_loop()
# 在新的线程中运行 asyncio 事件循环
asyncio_thread = threading.Thread(target=run_asyncio_loop, args=(new_loop,))
asyncio_thread.start()
# 等待线程完成
for thread in threads:
thread.join()
# 等待 asyncio 线程完成
asyncio_thread.join()
print(f"Final shared_resource value: {shared_resource}")
# 运行主程序
if __name__ == "__main__":
asyncio.run(main())
说明
- 共享资源和锁:
shared_resource
: 一个共享的全局资源。lock
: 用于保护对shared_resource
的访问,确保同一时间只有一个线程可以更新它。semaphore
: 信号量,用于限制同时访问某个资源的线程数量,这里设置为最多允许两个线程同时执行。
- 异步任务 (
async_task
):- 模拟异步操作的函数,通过
await asyncio.sleep(2)
暂停执行两秒钟。
- 模拟异步操作的函数,通过
- 线程工作函数 (
thread_worker
):- 每个线程启动时会打印开始信息。
- 通过
semaphore
来限制同时进入的线程数量。 - 通过
lock
来确保对shared_resource
的访问是线程安全的。 - 更新
shared_resource
后,线程打印更新后的值。
- 在线程中运行的
asyncio
事件循环 (run_asyncio_loop
):- 创建新的
asyncio
事件循环,并在该事件循环中运行两个异步任务。
- 创建新的
- 主函数 (
main
):- 创建和启动三个线程,每个线程运行
thread_worker
函数。 - 创建新的事件循环并在新线程中运行异步任务。
- 等待所有线程完成后,打印
shared_resource
的最终值。
- 创建和启动三个线程,每个线程运行
- 运行主程序:
- 使用
asyncio.run(main())
启动主程序。
- 使用
关键点总结
- 线程控制: 使用
threading.Thread
创建和管理线程。 - 同步机制: 使用
threading.Lock
和threading.Semaphore
控制线程间的同步和并发。 - 异步操作: 使用
asyncio
执行异步任务,并与多线程结合使用。
Selenium
关于选择
find_element
返回单个对象,find_elements
返回一个列表
在 find_element
等等中使用By时应导入
from selenium.webdriver.common.by import By
By有以下几种策略:
策略名 | 示例目标 | 解释 |
---|---|---|
CLASS_NAME | <div class="target"></div> | 寻找指定CLASS名的元素 |
CSS_SELECTOR | 请看下面详情 | 使用 CSS 选择器定位元素 |
ID | <div id="target"></div> | 寻找指定ID名的元素 |
LINK_TEXT | <a>target</a> | 寻找TEXT为目标的a链接(精确匹配) |
NAME | <input name="username" type="text" /> | 通过name属性来定位元素 |
PARTIAL_LINK_TEXT | <a>targetabababab</a> | 寻找TEXT为目标的a链接(模糊匹配) |
TAG_NAME | <target><target> | 找对应的标签 |
XPATH | 请看下面详情 | 使用XPATH语法进行搜索 |
CSS 选择器定位器解释
定位方式 | css格式 | 示例 | 说明 |
---|---|---|---|
id属性定位 | #id属性值 | #username | #代表id属性,username代表id对应的值。 |
class属性定位 | .class属性值 | .username | .代表class属性,username代表class对应的值 |
标签定位 | 标签 | input | 使用input标签定位,不过一般单独使用定位到元素,故不会单独使用 。它只能和其它方式结合使用 |
属性定位 | [属性名=值] | [type=‘password’] | []是固定格式,代表要使用属性定位,type是属性名,password是属性值 |
标签+id定位 | 标签#id属性值 | input#username | 标签为input ,id的属性值为username ,两者结合。 |
标签+class定位 | 标签.class属性值 | input.username | 标签为input ,class的属性值为username ,两者结合。 |
标签和属性集合定位 | 标签[属性名=值] | input[type=‘password’] | 标签为input , []括号内的为属性和值 。这种用法最多。 |
多属性定位 | [属性1=值1][属性2=值2] | [type=‘password’][id=‘password’] | 同时使用两个属性一起定位 ,这种情况用于一个属性定位不到,可以选择两个一起定位 。 |
XPATH语法
selenium操作流程
首先,实例化(对应浏览器)对象(此处为Edge)
from selenium import webdriver
bro = webdriver.Edge()
然后,发起 get
请求
bro.get('http://localhost:8080/test/')
此时,bro.page_source
内储存的就是页面数据,可以用 lxml
库解析,当然,推荐使用 webdriver
的 find_element
等操作进行查找
此时,也可以尝试运行一些JS:使用 execute_script()
函数:例:
# 把滚动条拉到最低
driver.execute_script('window.scrollTo(0, document.body.scrollHeight)')
这类函数有个表,不全可以补充
函数 | 解释 | 示例 |
---|---|---|
get() | 打开界面 | |
quit() | 关闭浏览器 | |
maximize_window() | 最大化窗口 | |
set_window_size() | 设置窗口参数 | set_window_size(600,800) |
back() | 后退到前一页 | |
forward() | 前进到后一页 | |
refresh() | 刷新页面 | |
clear() | 清除文本 | |
get_screenshot_as_file() | 页面截图 | get_screenshot_as_file(“foo.png”) |
当Selenium成功查找到之后,就可以进行操作了
函数 | 操作 |
---|---|
send_keys(str) | 模拟键盘输入 |
click() | 模拟鼠标点击 |
submit() | 提交表单(相当于"回车") |
ActionChains动作链
点击函数:
函数名 | 解释 |
---|---|
click() | 点击 |
context_click() | 右键 |
double_click() | 双击 |
click_and_hold() | 点住不放 |
release() | 放了 |
移动函数:
函数名 | 解释 |
---|---|
move_by_offset(xoffset, yoffset) | 将鼠标相对于上一次位置按指定偏移量移动 |
move_to_element(element) | 移动到某个元素上 |
move_to_element_with_offset(to_element, xoffset, yoffset) | 将鼠标移动到指定元素的偏移位置上 |
拖拽函数:
函数名 | 解释 |
---|---|
drag_and_drop(source,target) | 将一个元素拖拽到另一个元素的位置上 |
drag_and_drop_by(source, target) | 将源元素拖动到目标元素的中心位置上。 |
drag_and_drop_by_offset(source, xoffset, yoffset) | 将源元素拖动到指定的偏移位置上。 |
以上函数设置了了都不要忘记使用 perform()
执行哦~
接下来咱们说说Option这个函数()
Option()
此类定义如下
class Options(object):
def __init__(self):
# 设置 chrome 二进制文件位置
self._binary_location = ''
# 添加启动参数
self._arguments = []
# 添加扩展应用
self._extension_files = []
self._extensions = []
# 添加实验性质的设置参数
self._experimental_options = {}
# 设置调试器地址
self._debugger_address = None
不多解释,上示例
from selenium.webdriver import EdgeOptions
#实现无可视化界面的操作
edge_options = EdgeOptions()
edge_options.add_argument('--headless')
edge_options.add_argument('--disable-gpu')
以此类推,其他的请自行查找
phantomJs
没看不知道()
注意
在爬虫的时候如果遇到了屏幕分辨率不是100%的情况下(设置中)可能会出现定位偏差,需要先使用
# 因为屏幕缩放问题,会造成location标点错误,现在执行js,对页面进行缩放,100 占 150 的 0.666666666,以获取准确信息
bro.execute_script('document.body.style.zoom="0.666"')
此种方法设置页面缩放才可正确获取信息
HTML方面CSS属性记忆不清
有很多零碎属性记忆不清(以下是没记住的时候原来记的),在写网站的时候大多数情况下可以用F12实时查看CSS是否生效,会方便很多,网页中也支持点JS断点(Vue为啥也能点,怎么实现的 #呆)
标签
box-size
值
-
默认值,标准盒子模型。
width
与height
只包括内容的宽和高,不包括边框(border),内边距(padding),外边距(margin)。注意:内边距、边框和外边距都在这个盒子的外部。比如说,.box {width: 350px; border: 10px solid black;}
在浏览器中的渲染的实际宽度将是 370px。尺寸计算公式:
-
width
= 内容的宽度 -
height
= 内容的高度
宽度和高度的计算值都不包含内容的边框(border)和内边距(padding)。
-
-
width
和height
属性包括内容,内边距和边框,但不包括外边距。这是当文档处于 Quirks 模式 时 Internet Explorer 使用的盒模型。注意,填充和边框将在盒子内 , 例如,.box {width: 350px; border: 10px solid black;}
导致在浏览器中呈现的宽度为 350px 的盒子。内容框不能为负,并且被分配到 0,使得不可能使用 border-box 使元素消失。尺寸计算公式:-
width
= border + padding + 内容的宽度 -
height
= border + padding + 内容的高度
-
background-repeat
属性定义背景图像的重复方式。背景图像可以沿着水平轴,垂直轴,两个轴重复,或者根本不重复。
值
单值语法是完整的双值语法的简写:
单值 | 等价于双值 |
---|---|
repeat-x | repeat no-repeat |
repeat-y | no-repeat repeat |
repeat | repeat repeat |
space | space space |
round | round round |
no-repeat | no-repeat no-repeat |
在双值语法中,第一个值表示水平重复行为,第二个值表示垂直重复行为。下面是关于每一个值是怎么工作的具体说明:
值 | 描述 |
---|---|
repeat | 图像会按需重复来覆盖整个背景图片所在的区域。最后一个图像会被裁剪,如果它的大小不合适的话。 |
space | 图像会尽可能得重复,但是不会裁剪。第一个和最后一个图像会被固定在元素 (element) 的相应的边上,同时空白会均匀地分布在图像之间。background-position 属性会被忽视,除非只有一个图像能被无裁剪地显示。只在一种情况下裁剪会发生,那就是图像太大了以至于没有足够的空间来完整显示一个图像。 |
round | 随着允许的空间在尺寸上的增长,被重复的图像将会伸展 (没有空隙), 直到有足够的空间来添加一个图像。当下一个图像被添加后,所有的当前的图像会被压缩来腾出空间。例如,一个图像原始大小是 260px, 重复三次之后,可能会被伸展到 300px, 直到另一个图像被加进来。这样他们就可能被压缩到 225px.译者注:关键是浏览器怎么计算什么时候应该添加一个图像进来,而不是继续伸展。 |
no-repeat | 图像不会被重复 (因为背景图像所在的区域将可能没有完全被覆盖). 那个没有被重复的背景图像的位置是由background-position 属性来决定。 |
background-position
为每一个背景图片设置初始位置。这个位置是相对于由 background-origin
定义的位置图层的.
值
一个 <position>
定义一组 x/y 坐标(相对于一个元素盒子模型的边界),来放置项目(原文为 item)。它可以使用一到四个值进行定义。如果使用两个非关键字值,第一个值表示水平位置,第二个值表示垂直位置。如果仅指定一个值,则第二个值默认是 center
。如果使用三个或四个值,则长度百分比值是前面关键字值的偏移量。
一个值的语法: 值可能是:
-
关键字
center
,用来居中背景图片。 -
关键字
top
、left
、bottom
、right
中的一个。用来指定把这个项目(原文为 item)放在哪一个边界。另一个维度被设置成 50%,所以这个项目(原文为 item)被放在指定边界的中间位置。<length>
或<percentage>
。指定相对于左边界的 x 坐标,y 坐标被设置成 50%。
两个值的语法: 一个定义 x 坐标,另一个定义 y 坐标。每个值可以是:
-
关键字
top
、left
、bottom
、right
中的一个。如果这里给出left
或right
,那么这个值定义 x 轴位置,另一个值定义 y 轴位置。如果这里给出top
或bottom
,那么这个值定义 y 轴位置,另一个值定义 x 轴位置。 -
<length>
或<percentage>
。如果另一个值是left
或right
,则该值定义相对于顶部边界的 Y。如果另一个值是top
或bottom
,则该值定义相对于左边界的 X。如果两个值都是<length>
或<percentage>
值,则第一个定义 X,第二个定义 Y。 -
注意:如果一个值是
top
或bottom
,那么另一个值不可能是top
或bottom
。如果一个值是left
或right
,那么另一个值不可能是left
或right
。也就是说,例如,top top
和left right
是无效的。 -
排序:配对关键字时,位置并不重要,因为浏览器可以重新排序,写成
top left
或left top
其产生的效果是相同的。使用<length>
或<percentage>
与关键字配对时顺序非常重要,定义 X 的值放在前面,然后是定义 Y 的值,right 20px
和20px right
的效果是不相同的,前者有效但后者无效。left 20%
或20% bottom
是有效的,因为 X 和 Y 值已明确定义且位置正确。 -
默认值是
left top
或者0% 0%
。
三个值的语法: 两个值是关键字值,第三个是前面值的偏移量:
-
第一个值是关键字
top
、left
、bottom
、right
,或者center
。如果设置为left
或right
,则定义了 X。如果设置为top
或bottom
,则定义了 Y,另一个关键字值定义了 X。 -
<length>
或<percentage>
,如果是第二个值,则是第一个值的偏移量。如果是第三个值,则是第二个值的偏移量。 -
单个长度或百分比值是其前面的关键字值的偏移量。一个关键字与两个
<length>
或<percentage>
值的组合无效。
四个值的语法: 第一个和第三个值是定义 X 和 Y 的关键字值。第二个和第四个值是前面 X 和 Y 关键字值的偏移量:
- 第一个值和第三个值是关键字值
top
、left
、bottom
、right
之一。如果设置为left
或right
,则定义了 X。如果设置为top
或bottom
,则定义了 Y,另一个关键字值定义了 X。 - 第二个和第四个值是
<length>
或<percentage>
。第二个值是第一个关键字的偏移量。第四个值是第二个关键字的偏移量。
关于百分比:
给定背景图像位置的百分比偏移量是相对于容器的。值 0% 表示背景图像的左(或上)边界与容器的相应左(或上)边界对齐,或者说图像的 0% 标记将位于容器的 0% 标记上。值为 100% 表示背景图像的 右(或 下)边界与容器的 右(或 下)边界对齐,或者说图像的 100% 标记将位于容器的 100% 标记上。因此 50% 的值表示水平或垂直居中背景图像,因为图像的 50% 将位于容器的 50% 标记处。类似的,background-position: 25% 75%
表示图像上的左侧 25% 和顶部 75% 的位置将放置在距容器左侧 25% 和距容器顶部 75% 的容器位置。
基本上发生的情况是从相应的容器尺寸中减去背景图像尺寸,然后将结果值的百分比用作从左(或顶部)边界的直接偏移量。
(container width - image width) * (position x%) = (x offset value)
(container height - image height) * (position y%) = (y offset value)
以 X 轴为例,假设我们有一个 300px 宽的图像,我们在一个 100px 宽的容器中使用它,background-size
设置为 auto
:
100px - 300px = -200px (container & image difference)
因此,位置百分比为 -25%、0%、50%、100%、125%,我们得到这些图像到容器边界偏移值:
-200px * -25% = 50px
-200px * 0% = 0px
-200px * 50% = -100px
-200px * 100% = -200px
-200px * 125% = -250px
因此,对于我们的示例,使用这些结果值,让图像的左边界从容器的左边界偏移:
- + 50px(将图像左边界放在 100px 宽容器的中心)
- 0px(图像左边界与容器左边界重合)
- -100px (将图片相对容器左移 100px,这意味着图片中部的 100px 内容将出现在容器中)
- -200px (将图片相对容器左移 200px,这意味着图片右部分的 100px 内容将出现在容器中)
- -250px (将图片相对容器左移 250px,这意味着图片的右边界对齐容器的中线)
值得一提的是,如果你的 background-size
等于给定轴的容器大小,那么该轴的 百分比 位置将不起作用,因为“容器图像差异”将为零。你将需要使用绝对值进行偏移。
形式定义
初始值 | 0% 0% |
---|---|
适用元素 | 所有元素. It also applies to ::first-letter and ::first-line . |
是否是继承属性 | 否 |
Percentages | refer to the size of the background positioning area minus size of background image; size refers to the width for horizontal offsets and to the height for vertical offsets |
计算值 | 该简写所对应的每个属性: background-position-x : A list, each item consisting of: an offset given as a combination of an absolute length and a percentage, plus an origin keywordbackground-position-y : A list, each item consisting of: an offset given as a combination of an absolute length and a percentage, plus an origin keyword |
动画类型 | a repeatable list |
形式语法
background-position =
<bg-position>#
<bg-position> =
[ left | center | right | top | bottom | <length-percentage> ] |
[ left | center | right | <length-percentage> ] [ top | center | bottom | <length-percentage> ] |
[ center | [ left | right ] <length-percentage>? ] && [ center | [ top | bottom ] <length-percentage>? ]
<length-percentage> =
<length> |
<percentage>
background-attachment
属性决定背景图像的位置是在视口内固定,或者随着包含它的区块滚动。
语法
CSSCopy to Clipboard
/* 关键 属性值 */
background-attachment: scroll;
background-attachment: fixed;
background-attachment: local;
/* 全局 属性值 */
background-attachment: inherit;
background-attachment: initial;
background-attachment: unset;
取值
-
此关键属性值表示背景相对于视口固定。即使一个元素拥有滚动机制,背景也不会随着元素的内容滚动。
-
此关键属性值表示背景相对于元素的内容固定。如果一个元素拥有滚动机制,背景将会随着元素的内容滚动,并且背景的绘制区域和定位区域是相对于可滚动的区域而不是包含他们的边框。
-
此关键属性值表示背景相对于元素本身固定,而不是随着它的内容滚动(对元素边框是有效的)。
特殊语句的对象差异
justify-content
和justify-item
一个针对多段,一个针对单个的
align-content
和align-item
同上
优先级
!important
提权功能,提高权重/优先级到 最高
伪类
nth-child
根据元素在父元素的子元素列表中的索引来选择元素。换言之,:nth-child()
选择器根据父元素内的所有兄弟元素的位置来选择子元素。
下标从1开始
现在战况
网站开发
入门了SpringBoot和Vue3,正在做一个小网页
用了Element-plus和VUE之后就有点懒,不想学JS的AJAXS和CSS了 #悲伤
学了SpringBoot感觉Python还是太难了(bushi)
命名还不是很规范,多看看别人的#乐
还没上传到github,等完善一点吧…感兴趣的同学可以@我瞧一瞧
如果有什么问题可以@咱,让咱也瞧瞧 #强烈的渴望