Py爬虫的一些总结

Python方面

有时候会忘记,要查一下字典,相对于HTML的CSS来说基本没问题。

下面有几个注意点:

是上传到图床的图片 #乐 看不到估计是图床崩了

requests

前言

此物用之简易,勿多言,其中道理可自源码观其注释而得(码字太多有点累)

快速入手

*(建议搭配JSON食用口味更佳)*

requests 的开始,是从 requests.post 的,其中,有三常用项

参数名解释示例
url网站URLhttps://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_listrandom.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等待所有进程池中的工作进程完成。必须在 closeterminate 之后调用。
imap返回一个迭代器,它按顺序获取给定函数应用于可迭代对象每个元素后的结果,逐个生成结果并保持处理顺序。
imap_unordered返回一个迭代器,它获取给定函数应用于可迭代对象每个元素后的结果,结果顺序是不确定的(即异步生成结果)。
get获取 apply_asyncmap_asyncstarmap_async 返回的 AsyncResult 对象的结果(阻塞直到任务完成)。
ready检查 AsyncResult 是否已经完成并可用。
wait等待 AsyncResult 对象的任务完成,可以选择设置超时时间。
successful检查 AsyncResult 对象的任务是否成功完成。
常用函数简介
  • 同步 vs 异步
    • 同步方法(applymapstarmap)会阻塞主进程,直到所有任务完成。
    • 异步方法(apply_asyncmap_asyncstarmap_async)不会阻塞主进程,立即返回 AsyncResult 对象,可以通过 get 方法获取结果。
  • map 系列
    • mapmap_async 作用于单个参数的函数和可迭代对象。
    • starmapstarmap_async 作用于带有多个参数的函数,每个参数的组合必须打包成元组或列表。
  • 结果处理
    • imapimap_unordered 返回迭代器,可以逐步处理结果。imap 保持原始顺序,而 imap_unordered 则不保证顺序。
  • 进程管理
    • closeterminatejoin 用于管理进程池的生命周期。closeterminate 停止进程池接受新任务,join 等待所有任务完成。
异步与非异步示例
使用 Pool.applyPool.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.mapPool.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.starmapPool.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.Eventasyncio.Queueasyncio.Lockasyncio.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())
示例解释
  1. asyncio.Queue:
    • 用于在生产者和消费者之间传递数据。生产者将数据放入队列中,消费者从队列中取出数据。
    • producer 协程中,生产者将数据项放入队列中。
    • consumer 协程中,消费者从队列中获取数据项。
  2. asyncio.Event:
    • 用于协调任务,通知消费者生产已经完成。
    • 生产者在完成生产后调用 event.set(),通知所有等待事件的消费者可以开始消费。
  3. asyncio.Lock:
    • 用于控制对共享资源(队列)的访问,确保同一时间只有一个消费者能从队列中取出数据。
    • 在消费者中使用 async with lock 以确保对队列的访问是线程安全的。
  4. asyncio.Semaphore:
    • 用于限制并发任务的数量。信号量的计数器设置为 2,表示最多允许两个消费者同时执行。
    • 在消费者中使用 async with semaphore 限制并发数量。
对于协程的理解
协程的执行和调度

asyncio 中,协程的执行和调度是通过事件循环管理的。以下是协程调度和交替执行的关键点:

  1. 事件循环管理协程:
    • 事件循环负责管理和调度协程的执行。协程可以挂起(例如等待 I/O 操作或使用 await),在挂起期间,事件循环会调度其他协程运行。
  2. 协程的挂起和恢复:
    • 当一个协程在执行 await 或等待 I/O 操作时,它会被挂起,事件循环会暂停它的执行,转而执行其他准备好的协程。
    • 一旦等待的操作完成,事件循环会恢复挂起的协程,并继续执行它的剩余部分。
  3. 信号量和锁的作用:
    • 使用 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()

说明

  1. 全局变量和同步机制:
    • shared_resource: 用于演示线程对共享资源的访问。
    • lock: 互斥锁,确保对 shared_resource 的访问是线程安全的。
    • semaphore: 信号量,限制同时进入某个代码块的线程数量。
    • rlock: 可重入锁,允许线程在持有锁时再次获得它。
    • condition: 条件变量,用于线程间的等待和通知。
    • barrier: 屏障,用于等待多个线程到达某个同步点。
  2. 线程工作函数 (thread_worker):
    • 使用信号量控制并发。
    • 使用锁保护对 shared_resource 的访问。
    • 使用可重入锁,演示可重入锁的特性。
    • 使用条件变量,等待通知并在收到通知后恢复执行。
  3. 屏障线程函数 (barrier_worker):
    • 每个线程模拟工作后,等待其他线程到达屏障。所有线程到达后,屏障会解除,线程继续执行。
  4. 条件变量通知函数 (condition_notifier):
    • 在等待了一段时间后,通知所有在条件变量上等待的线程。
  5. 主函数 (main):
    • 启动线程池,每个线程执行 thread_worker 函数。
    • 启动一个条件变量通知线程,用于通知等待条件变量的线程。
    • 启动屏障线程,每个线程执行 barrier_worker 函数。
    • 等待所有线程完成,包括条件变量通知线程和屏障线程。
  6. 运行主程序:
    • 使用 main() 函数启动所有线程和操作。

关键点总结

  • 线程控制: 使用 threading.Thread 创建和管理线程。
  • 同步机制: 使用 threading.Lockthreading.Semaphorethreading.RLockthreading.Conditionthreading.Barrier 等同步工具来控制并发和资源访问。
  • 条件变量和屏障: 使用条件变量和屏障来实现线程间的通知和同步。

写的不错,下次继续用(乐)

asynciothreading的综合运用(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())

说明

  1. 共享资源和锁:
    • shared_resource: 一个共享的全局资源。
    • lock: 用于保护对 shared_resource 的访问,确保同一时间只有一个线程可以更新它。
    • semaphore: 信号量,用于限制同时访问某个资源的线程数量,这里设置为最多允许两个线程同时执行。
  2. 异步任务 (async_task):
    • 模拟异步操作的函数,通过 await asyncio.sleep(2) 暂停执行两秒钟。
  3. 线程工作函数 (thread_worker):
    • 每个线程启动时会打印开始信息。
    • 通过 semaphore 来限制同时进入的线程数量。
    • 通过 lock 来确保对 shared_resource 的访问是线程安全的。
    • 更新 shared_resource 后,线程打印更新后的值。
  4. 在线程中运行的 asyncio 事件循环 (run_asyncio_loop):
    • 创建新的 asyncio 事件循环,并在该事件循环中运行两个异步任务。
  5. 主函数 (main):
    • 创建和启动三个线程,每个线程运行 thread_worker 函数。
    • 创建新的事件循环并在新线程中运行异步任务。
    • 等待所有线程完成后,打印 shared_resource 的最终值。
  6. 运行主程序:
    • 使用 asyncio.run(main()) 启动主程序。

关键点总结

  • 线程控制: 使用 threading.Thread 创建和管理线程。
  • 同步机制: 使用 threading.Lockthreading.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 库解析,当然,推荐使用 webdriverfind_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

  • content-box

    默认值,标准盒子模型。widthheight 只包括内容的宽和高,不包括边框(border),内边距(padding),外边距(margin)。注意:内边距、边框和外边距都在这个盒子的外部。比如说,.box {width: 350px; border: 10px solid black;} 在浏览器中的渲染的实际宽度将是 370px。

    尺寸计算公式:

    • width = 内容的宽度

    • height = 内容的高度

    宽度和高度的计算值都不包含内容的边框(border)和内边距(padding)。

  • border-box

    widthheight 属性包括内容,内边距和边框,但不包括外边距。这是当文档处于 Quirks 模式 时 Internet Explorer 使用的盒模型。注意,填充和边框将在盒子内 , 例如, .box {width: 350px; border: 10px solid black;} 导致在浏览器中呈现的宽度为 350px 的盒子。内容框不能为负,并且被分配到 0,使得不可能使用 border-box 使元素消失。尺寸计算公式:

    • width = border + padding + 内容的宽度

    • height = border + padding + 内容的高度

background-repeat

属性定义背景图像的重复方式。背景图像可以沿着水平轴,垂直轴,两个轴重复,或者根本不重复。

单值语法是完整的双值语法的简写:

单值等价于双值
repeat-xrepeat no-repeat
repeat-yno-repeat repeat
repeatrepeat repeat
spacespace space
roundround round
no-repeatno-repeat no-repeat

在双值语法中,第一个值表示水平重复行为,第二个值表示垂直重复行为。下面是关于每一个值是怎么工作的具体说明:

描述
repeat图像会按需重复来覆盖整个背景图片所在的区域。最后一个图像会被裁剪,如果它的大小不合适的话。
space图像会尽可能得重复,但是不会裁剪。第一个和最后一个图像会被固定在元素 (element) 的相应的边上,同时空白会均匀地分布在图像之间。background-position属性会被忽视,除非只有一个图像能被无裁剪地显示。只在一种情况下裁剪会发生,那就是图像太大了以至于没有足够的空间来完整显示一个图像。
round随着允许的空间在尺寸上的增长,被重复的图像将会伸展 (没有空隙), 直到有足够的空间来添加一个图像。当下一个图像被添加后,所有的当前的图像会被压缩来腾出空间。例如,一个图像原始大小是 260px, 重复三次之后,可能会被伸展到 300px, 直到另一个图像被加进来。这样他们就可能被压缩到 225px.译者注:关键是浏览器怎么计算什么时候应该添加一个图像进来,而不是继续伸展。
no-repeat图像不会被重复 (因为背景图像所在的区域将可能没有完全被覆盖). 那个没有被重复的背景图像的位置是由background-position属性来决定。

background-position

为每一个背景图片设置初始位置。这个位置是相对于由 background-origin 定义的位置图层的.

<position>

一个 <position> 定义一组 x/y 坐标(相对于一个元素盒子模型的边界),来放置项目(原文为 item)。它可以使用一到四个值进行定义。如果使用两个非关键字值,第一个值表示水平位置,第二个值表示垂直位置。如果仅指定一个值,则第二个值默认是 center。如果使用三个或四个值,则长度百分比值是前面关键字值的偏移量。

一个值的语法: 值可能是:

  • 关键字 center,用来居中背景图片。

  • 关键字 topleftbottomright 中的一个。用来指定把这个项目(原文为 item)放在哪一个边界。另一个维度被设置成 50%,所以这个项目(原文为 item)被放在指定边界的中间位置。<length><percentage>。指定相对于左边界的 x 坐标,y 坐标被设置成 50%。

两个值的语法: 一个定义 x 坐标,另一个定义 y 坐标。每个值可以是:

  • 关键字 topleftbottomright 中的一个。如果这里给出 leftright,那么这个值定义 x 轴位置,另一个值定义 y 轴位置。如果这里给出 topbottom,那么这个值定义 y 轴位置,另一个值定义 x 轴位置。

  • <length><percentage>。如果另一个值是 leftright,则该值定义相对于顶部边界的 Y。如果另一个值是 topbottom,则该值定义相对于左边界的 X。如果两个值都是 <length><percentage> 值,则第一个定义 X,第二个定义 Y。

  • 注意:如果一个值是 topbottom,那么另一个值不可能是 topbottom。如果一个值是 leftright,那么另一个值不可能是 leftright。也就是说,例如,top topleft right 是无效的。

  • 排序:配对关键字时,位置并不重要,因为浏览器可以重新排序,写成 top leftleft top 其产生的效果是相同的。使用 <length><percentage> 与关键字配对时顺序非常重要,定义 X 的值放在前面,然后是定义 Y 的值, right 20px20px right 的效果是不相同的,前者有效但后者无效。left 20%20% bottom 是有效的,因为 X 和 Y 值已明确定义且位置正确。

  • 默认值是 left top 或者 0% 0%

三个值的语法: 两个值是关键字值,第三个是前面值的偏移量:

  • 第一个值是关键字 topleftbottomright,或者 center。如果设置为 leftright,则定义了 X。如果设置为 topbottom,则定义了 Y,另一个关键字值定义了 X。

  • <length><percentage>,如果是第二个值,则是第一个值的偏移量。如果是第三个值,则是第二个值的偏移量。

  • 单个长度或百分比值是其前面的关键字值的偏移量。一个关键字与两个 <length><percentage> 值的组合无效。

四个值的语法: 第一个和第三个值是定义 X 和 Y 的关键字值。第二个和第四个值是前面 X 和 Y 关键字值的偏移量:

  • 第一个值和第三个值是关键字值 topleftbottomright 之一。如果设置为 leftright,则定义了 X。如果设置为 topbottom,则定义了 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.
是否是继承属性
Percentagesrefer 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;
取值
  • fixed

    此关键属性值表示背景相对于视口固定。即使一个元素拥有滚动机制,背景也不会随着元素的内容滚动。

  • local

    此关键属性值表示背景相对于元素的内容固定。如果一个元素拥有滚动机制,背景将会随着元素的内容滚动,并且背景的绘制区域和定位区域是相对于可滚动的区域而不是包含他们的边框。

  • scroll

    此关键属性值表示背景相对于元素本身固定,而不是随着它的内容滚动(对元素边框是有效的)。

特殊语句的对象差异

justify-contentjustify-item一个针对多段,一个针对单个的

align-contentalign-item同上

优先级

!important

提权功能,提高权重/优先级到 最高

伪类

nth-child

根据元素在父元素的子元素列表中的索引来选择元素。换言之,:nth-child() 选择器根据父元素内的所有兄弟元素的位置来选择子元素。

下标从1开始

现在战况

网站开发

入门了SpringBoot和Vue3,正在做一个小网页

制作的工具

用了Element-plus和VUE之后就有点懒,不想学JS的AJAXS和CSS了 #悲伤

学了SpringBoot感觉Python还是太难了(bushi)

命名还不是很规范,多看看别人的#乐

还没上传到github,等完善一点吧…感兴趣的同学可以@我瞧一瞧

在这里插入图片描述
如果有什么问题可以@咱,让咱也瞧瞧 #强烈的渴望

  • 15
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Py微博关键词全文爬虫是一种使用Python编程语言开发的工具,用于在微博平台上进行关键词的全文检索和爬取相关内容。CSDN是一个知名的技术社区,提供各种IT领域的学习资源和技术交流平台。 Py微博关键词全文爬虫可以通过调用微博的API接口,根据设定的关键词在微博平台上进行全文搜索。它可以获取相关微博的文本内容、图片、视频以及其他相关信息。使用Python编程,可以轻松编写程序实现对微博平台上特定关键词的监控和爬取。 CSDN作为一家技术社区,提供了大量的技术博客、文章和论坛帖子。通过在CSDN上搜索关键词,可以找到与该关键词相关的技术资讯、教程、研究成果等。同时,CSDN还提供了各种技术交流的平台,用户可以在这里提问、回答问题、分享经验和交流意见。 通过结合Py微博关键词全文爬虫和CSDN的使用,可以实现对特定关键词在微博平台和CSDN社区上的全文搜索和爬取。这样可以快速获取相关资讯、了解最新技术动态,同时也可以进行技术问题的交流和解答。这对于从事技术工作的人员和对技术感兴趣的人来说,是一个非常有用的工具和资源。 ### 回答2: py微博关键词全文爬虫是一种利用Python语言编写的程序,用于在微博上搜索特定的关键词,并收集相关内容的技术。CSDN是一个IT技术社区,提供了很多关于Python编程和爬虫技术的文章和教程。 通过py微博关键词全文爬虫,我们可以实现以下功能: 1. 搜索特定的关键词:我们可以输入想要搜索的关键词,比如"Python编程"或"人工智能"等,程序会在微博上进行搜索,并返回相关的内容。 2. 收集相关内容:通过爬虫技术,我们可以获取到搜索结果中包含关键词的微博内容。包括微博的文字、图片、视频等信息。 3. 分析和处理数据:我们可以对爬取到的数据进行分析和处理,比如提取关键词的出现频率、分析用户的情感倾向等。这些分析可以帮助我们了解特定话题在微博上的热度和影响力。 4. 数据展示和保存:我们可以将分析处理后的数据展示在网页上或保存到数据库中,以便后续的使用和参考。 总结来说,py微博关键词全文爬虫是一种利用Python编程语言实现的技术,利用它可以搜索并收集微博上特定关键词相关的内容,并对数据进行进一步的分析和处理。这对于了解和研究特定话题在微博上的传播和影响力具有很大的帮助。CSDN作为一个IT技术社区,在这方面提供了很多有关Python编程和爬虫技术的资源和教程,可以用来学习和进一步提升相关的技能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值