技术标签: 爬虫 学习 python selenium 测试工具 职场和发展 开发语言
在数字化的时代,网络已经成为了我们获取信息、数据和知识的首选渠道。而对于经管类的科研工作者而言,获取和处理来自网络的数据不仅仅是一种能力,更是研究的必要环节。但面对复杂多变的网络环境,传统的爬虫技术可能已经无法满足我们的需求,特别是在遇到需要模拟用户交互或数据动态加载的网站时。那么,有没有一种工具可以轻松、高效地解决这些问题呢?答案是肯定的——那就是Selenium。
为什么选择Selenium?
Selenium不同于常规的爬虫工具。它最初是为了网页自动化测试而设计的,这意味着它可以模拟几乎所有的用户行为:点击、滚动、键入、拖放等。这使得Selenium能够轻松应对各种复杂的网页结构和交互场景。对于那些数据是通过JavaScript动态加载,或者需要登录后才能访问的网站,Selenium都能够胜任。
Selenium与其他爬虫工具的对比
与传统的爬虫工具比如BeautifulSoup或Scrapy相比,Selenium的优势在于它可以模拟真实的浏览器环境,这意味着我们可以直接看到爬虫的行为和结果,也更容易调试。而且,由于Selenium支持多种编程语言和浏览器,它的适用范围非常广泛。当然,这也意味着使用Selenium可能需要更多的资源和学习成本,但对于需要模拟用户交互或处理动态加载数据的任务,这些成本是值得的。
在开始使用Selenium进行爬取之前,确保你的环境配置无误是非常重要的。一个良好的开发环境可以大大提高效率,减少在后续开发中可能出现的问题。
Python环境的搭建:
Python,作为一种广泛使用的编程语言,其强大的库支持和友好的语法使得它成为爬虫开发的首选。
安装Python: 如果你还没有安装Python,可以访问Python官网下载合适的版本。推荐使用Python3,因为它拥有更多的特性和更好的支持。
使用Anaconda: Anaconda是一个流行的Python发行版,它内置了大量的科学计算库,非常适合数据分析和科研工作。安装Anaconda后,你可以利用conda命令轻松管理Python环境和包。
Selenium库的安装:
有了Python,接下来就是安装Selenium库。这一步非常简单,只需使用pip命令即可:
pip install selenium
这会安装Selenium的最新版本。安装完成后,你可以使用以下命令来验证是否安装成功:
import selenium
print(selenium.__version__)
WebDriver的选择与配置:
为了让Selenium控制浏览器,我们需要一个名为WebDriver的中间件。根据你的浏览器选择相应的WebDriver。
Chrome: 对于Chrome浏览器,你需要下载ChromeDriver。这里我们再给大家提供一个更方便的下载途径:https://googlechromelabs.github.io/chrome-for-testing/#stable
Firefox: 对于Firefox浏览器,选择GeckoDriver。
其他: Selenium还支持Safari、Edge等浏览器,但Chrome和Firefox是最常用的。
下载完成后,确保WebDriver的路径已添加到系统的PATH中,或者在初始化例如webdriver.Chrome()
时指定其路径。例如:
from selenium import webdriver
driver = webdriver.Chrome(executable_path='/path/to/chromedriver')
完成上述步骤后,你的Selenium环境应该已经配置完毕,接下来可以开始编写你的第一个Selenium爬虫!
掌握Selenium的基础操作是进行任何爬虫项目的基础。这部分内容将带你了解如何使用Selenium控制浏览器进行常见的操作,如启动、关闭浏览器,页面导航,以及窗口和标签页的管理。
启动浏览器与关闭浏览器:
使用Selenium的第一步是启动一个浏览器实例。以下是如何做到这一点的指南:
启动Chrome浏览器:
from selenium import webdriver
driver = webdriver.Chrome(executable_path='/path/to/chromedriver')
启动Firefox浏览器:
from selenium import webdriver
driver = webdriver.Firefox(executable_path='/path/to/geckodriver')
当你完成爬虫任务后,别忘了关闭浏览器。这有两种方式:
driver.close()
: 这将关闭当前浏览器窗口。
driver.quit()
: 这将退出浏览器进程,关闭所有相关窗口。
页面导航:前进、后退、刷新
在许多情况下,我们需要进行页面导航,如访问一个URL、后退或刷新页面。
访问URL:
driver.get("https://www.example.com")
后退:
driver.back()
前进:
driver.forward()
刷新页面:
driver.refresh()
窗口与标签页的管理:
当你进行爬取任务时,可能会遇到多个窗口或标签页。Selenium提供了方法来切换和管理这些窗口。
获取所有窗口句柄:
windows = driver.window_handles
windows
是一个列表,其中包含所有窗口的句柄。
切换到另一个窗口:
driver.switch_to.window(windows[1])
以上代码切换到第二个窗口。
关闭当前窗口并切换回原始窗口:
driver.close()
driver.switch_to.window(windows[0])
这只是Selenium的冰山一角。通过这些基础操作,你已经可以进行大部分的页面导航和浏览器控制。在接下来的章节中,我们将学习如何与网页上的元素进行交互,这是爬虫的核心内容。
成功进行爬虫任务的关键在于准确地定位和操作页面上的元素。Selenium提供了多种方法来定位页面元素,以满足不同的需求和场景。在这一部分,我们将详细介绍这些方法,以及如何在Selenium 4中使用它们。
ID、Name、Class
这些是最基本且常用的元素定位方法,大多数网页元素都有这些属性。
通过ID定位:
在Selenium 4中,find_elements_by_id
的方法已经不再推荐使用,而是建议使用以下方式:
from selenium.webdriver.common.by import By
element = driver.find_element(By.ID, "your_element_id")
通过Name定位:
element = driver.find_element(By.NAME, "your_element_name")
通过Class Name定位:
element = driver.find_element(By.CLASS_NAME, "your_element_class_name")
XPath与CSS Selector
对于更复杂的页面结构,特别是当元素没有ID、Name或Class时,XPath和CSS Selector是非常有用的工具。
通过XPath定位:
XPath是一种定义在XML文档中查找信息的语言。在网页爬虫中,它常用于定位没有明确标识的元素。
element = driver.find_element(By.XPATH, "//tagname[@attribute='value']")
通过CSS Selector定位:
CSS Selector是另一种非常强大的定位方法,特别是在需要与样式表交互的时候。
element = driver.find_element(By.CSS_SELECTOR, "tagname[attribute='value']")
复合定位策略
在某些情况下,一个单一的定位策略可能不足以准确找到一个元素。此时,可以使用复合策略来结合多个条件。
例如,如果需要找到一个同时满足特定ID和特定Class的元素,可以使用以下的XPath:
element = driver.find_element(By.XPATH, "//*[@id='your_id' and @class='your_class_name']")
使用By对象进行定位
如前所述,在Selenium 4中,推荐使用By对象进行元素的定位。它不仅提供了一种更一致和简洁的方式来定位元素,还支持多种定位策略,如ID、Name、XPath、CSS Selector等。
成功定位页面元素后,真正的魔法就是与这些元素进行交互,从而实现数据抓取、自动填表、自动点击等操作。这一部分将教你如何使用Selenium执行这些交互。
元素的点击、输入、清除
一旦你定位到一个元素,你可以执行许多操作,如点击、输入和清除。
点击元素:
如果元素是一个按钮或链接,你可以使用click
方法来点击它:
element = driver.find_element(By.ID, "button_id")
element.click()
输入文本:
对于文本框,你可以使用send_keys
方法来输入数据:
textbox = driver.find_element(By.NAME, "textbox_name")
textbox.send_keys("Hello, Selenium!")
清除文本框内容:
如果你需要先清除文本框的当前内容再输入,可以使用clear
方法:
textbox.clear()
textbox.send_keys("New Text Here!")
下拉框、单选框、复选框操作
对于这些特殊的输入元素,Selenium提供了专门的方法来处理它们。
下拉框:
使用Select
类来处理下拉框元素:
from selenium.webdriver.support.ui import Select
dropdown = Select(driver.find_element(By.ID, "dropdown_id"))
dropdown.select_by_visible_text("Option Text")
单选框和复选框:
单选框和复选框的操作与普通按钮类似,但你可能需要先判断它的状态:
checkbox = driver.find_element(By.ID, "checkbox_id")
if not checkbox.is_selected():
checkbox.click()
执行JavaScript代码
有时,Selenium的内置方法可能不足以满足你的需要,或者某些操作在Selenium中难以实现。在这种情况下,直接执行JavaScript代码可能是一个好方法:
driver.execute_script("arguments[0].scrollIntoView();", element)
上面的代码会滚动页面直到element
元素出现在视窗中。
另一个例子,如果你需要更改页面上元素的属性,例如隐藏的文本框:
driver.execute_script("document.getElementById('hidden_textbox').style.display = 'block';")
在自动化过程中,等待是一个非常关键的环节。由于网络延迟、服务器处理时间、客户端渲染时间等原因,页面上的元素可能不会立即可用。因此,正确的等待策略是确保爬虫稳定性的关键。Selenium提供了几种等待方法,以适应各种场景。
隐式等待
隐式等待会指定一个固定的时间,让WebDriver在查找元素时等待指定的时间。如果在这段时间内元素可用,则进行下一步;否则,它会抛出一个NoSuchElementException
。
driver.implicitly_wait(10) # 10秒
这里,浏览器会在尝试找到任何元素之前等待最多10秒。如果在10秒内元素出现了,它会立即继续;否则,到达10秒后,将抛出异常。
显式等待
与隐式等待相反,显式等待允许你为某个特定的条件设定等待时间。这是一种更智能的等待方法,因为它会等待某个条件成立,而不仅仅是固定的时间。
为了使用显式等待,你需要结合使用WebDriverWait
和预期条件(expected_conditions
):
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myElementId"))
)
上面的代码会等待10秒,直到ID为myElementId
的元素出现在页面上。
自定义等待条件
除了Selenium提供的预期条件外,你还可以定义自己的等待条件:
def element_has_css_class(css_class):
def predicate(driver):
element = driver.find_element(By.ID, "myElementId")
return css_class in element.get_attribute("class")
return predicate
element = WebDriverWait(driver, 10).until(element_has_css_class("myClass"))
上面的代码定义了一个自定义等待条件,它会等待元素具有特定的CSS类。
在Web自动化的过程中,你可能会遇到一些特殊的页面元素和场景,如iFrames、弹出窗口、警告框和Cookies。正确地处理这些元素是确保自动化脚本稳定运行的关键。在本节中,我们将介绍如何使用Selenium处理这些情境。
处理IFrame与弹出窗口
IFrames:
如果一个元素位于iFrame内部,直接定位这个元素会失败。首先,你需要切换到这个iFrame:
driver.switch_to.frame("iframe_name_or_id")
或者,如果你有这个iFrame的WebElement:
iframe_element = driver.find_element(By.TAG_NAME, "iframe")
driver.switch_to.frame(iframe_element)
完成iFrame中的操作后,切换回主内容:
driver.switch_to.default_content()
弹出窗口:
当点击某些链接或按钮时,可能会打开新的浏览器窗口或选项卡。你可以使用以下方式在它们之间切换:
# 切换到新打开的窗口
driver.switch_to.window(driver.window_handles[-1])
# 切换回原始窗口
driver.switch_to.window(driver.window_handles[0])
处理Alerts和确认框
Alerts:
网页上的警告框(或确认框)是特殊的对话框,不能像普通元素那样进行交互。你可以这样操作它们:
alert = driver.switch_to.alert
alert_text = alert.text
alert.accept() # 点击"OK"
确认框:
对于确认框,除了接受外,你还可以选择取消:
alert.dismiss() # 点击"Cancel"
处理Cookies
Cookies是网站存储在浏览器上的小片数据。Selenium允许你读取和设置这些Cookies。
获取所有Cookies:
all_cookies = driver.get_cookies()
添加一个Cookie:
driver.add_cookie({
"name": "my_cookie_name",
"value": "my_cookie_value"
})
删除一个Cookie:
driver.delete_cookie("my_cookie_name")
删除所有Cookies:
driver.delete_all_cookies()
在现代网站中,数据经常是动态加载的,而不是与页面一起立即加载。这通常是通过AJAX技术实现的。为了有效地抓取这些数据,我们需要了解如何处理这些动态加载的内容。
理解AJAX
AJAX(异步JavaScript和XML)是一种技术,允许Web页面在不重新加载整个页面的情况下从服务器请求额外的数据。这意味着当你用Selenium访问一个页面时,即使页面似乎已经加载完成,某些数据可能仍然在后台加载。
例如,许多网站的滚动功能是基于AJAX的:当你滚动到页面底部时,更多内容会自动加载。或者,当你点击一个按钮或选项卡时,内容可能会动态更改,而不是导航到新的页面。
WebDriverWait与expected_conditions的结合使用
为了有效地处理AJAX加载的数据,我们需要结合使用WebDriverWait
和expected_conditions
,这样我们可以等待特定的元素或条件变得可用。
等待元素出现:
当新的内容被动态加载到页面时,我们可以等待这些元素出现:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "newlyLoadedElementId"))
)
等待元素可见:
有时元素可能存在于DOM中,但不可见。在这种情况下,我们需要等待元素变得可见:
element = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.ID, "newlyLoadedElementId"))
)
其他常用条件:
等待元素变得可以点击:
python element = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.ID, "buttonId")) )
等待所有元素都加载完成(对于列表):
python elements = WebDriverWait(driver, 10).until( EC.presence_of_all_elements_located((By.CLASS_NAME, "itemClass")) )
在对Selenium有了一定的熟悉之后,你可能会想探索一些高级技巧来增强你的自动化脚本或爬虫的功能。在本节中,我们将讨论两个高级主题:使用代理和WebDriver的并发执行。
使用Proxy代理
使用代理服务器可以为你的Selenium爬虫提供多种好处,如隐藏真实IP地址、绕过地区限制或分布式爬取。以下是如何配置Selenium使用代理:
使用Chrome:
from selenium import webdriver
PROXY = "127.0.0.1:8080" # 示例代理IP和端口
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument(f"--proxy-server={PROXY}")
driver = webdriver.Chrome(options=chrome_options)
使用Firefox:
from selenium import webdriver
PROXY = "127.0.0.1:8080"
firefox_capabilities = webdriver.DesiredCapabilities.FIREFOX
firefox_capabilities['marionette'] = True
firefox_capabilities['proxy'] = {
"proxyType": "MANUAL",
"httpProxy": PROXY,
"ftpProxy": PROXY,
"sslProxy": PROXY
}
driver = webdriver.Firefox(capabilities=firefox_capabilities)
WebDriver的并发执行
当你需要在多个浏览器实例中同时执行任务时,可以使用Python的多线程或多进程。但请注意,大量并发可能会导致系统变慢或不稳定。
使用threading
模块:
import threading
from selenium import webdriver
def task():
driver = webdriver.Chrome()
driver.get("http://example.com")
# ... 其他操作
driver.quit()
threads = []
for _ in range(5): # 创建5个线程
t = threading.Thread(target=task)
threads.append(t)
t.start()
for thread in threads:
thread.join()
使用concurrent.futures
模块:
更现代的方法是使用concurrent.futures
,它提供了一个更高级的接口来管理线程和进程:
from concurrent.futures import ThreadPoolExecutor
from selenium import webdriver
def task():
driver = webdriver.Chrome()
driver.get("http://example.com")
# ... 其他操作
driver.quit()
with ThreadPoolExecutor(max_workers=5) as executor:
for _ in range(5):
executor.submit(task)
随着你在Selenium自动化领域的深入,你可能会想要探索更多的高级特性来增强你的脚本。这一节将深入探讨如何使用代理、并发执行WebDriver实例以及如何进行截图和录屏。
使用Proxy代理
代理是Web请求的中介,它可以帮助你隐藏真实IP、绕过地理限制或加速请求。要在Selenium中设置代理,你可以使用webdriver.Proxy()
。
示例(对于Chrome浏览器):
from selenium import webdriver
PROXY = "your_proxy_ip:port"
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument(f"--proxy-server={PROXY}")
driver = webdriver.Chrome(options=chrome_options)
这样,所有通过Selenium发出的请求都将通过指定的代理服务器。
WebDriver的并发执行
并发执行是同时运行多个WebDriver实例的技术。Python的threading
或multiprocessing
模块都可以实现这一点。但要记住,过多的并发操作可能导致你的机器过载或被目标网站封锁。
简单的示例使用threading
:
import threading
from selenium import webdriver
def start_browser(url):
driver = webdriver.Chrome()
driver.get(url)
# ...其他操作...
driver.quit()
urls = ["http://example.com", "http://anotherexample.com"]
threads = []
for url in urls:
thread = threading.Thread(target=start_browser, args=(url,))
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
截图
截图:
Selenium提供了一个简单的方法来截取当前浏览器窗口的屏幕截图:
driver.get("http://example.com")
driver.save_screenshot("screenshot.png")
在我们深入探讨Selenium的多个方面之后,很重要的一点是认识到,像所有工具一样,Selenium在使用时需要遵循一些基本的注意事项和最佳实践。此外,网页抓取和自动化不仅受到技术限制,还受到法律和道德的约束。
注意事项与最佳实践
尊重Robots.txt: 大多数网站都有一个robots.txt
文件,其中指定了哪些页面可以爬取,哪些不可以。尽管Selenium不像其他爬虫库那样自动遵循它,但你仍应当遵守其规定。
不过度请求: 大量的快速连续请求可能会导致服务器过载,甚至可能导致你的IP被封锁。合理地添加延迟和限制请求频率是一个好习惯。
错误处理: 网页结构的更改、临时的网络问题或其他外部因素都可能导致你的脚本出错。确保在你的脚本中添加适当的错误处理机制,如try-except块。
保存数据: 确保经常保存你的爬取结果,以避免由于意外中断而丢失数据。
法律与道德约束
法律约束: 在许多国家和地区,无授权的数据抓取可能是非法的,特别是当这些数据用于商业目的时。确保你了解和遵守相关的数据抓取和隐私法规。
道德问题: 即使技术上可以执行某个操作,也不意味着应该这样做。爬取个人数据、滥用资源或其他潜在的伤害行为都应当避免。
获取许可: 如果你不确定是否可以抓取某个网站,与该网站的管理员联系并请求许可可能是最好的办法。
回首本篇教程,我们深入探讨了Selenium的各种功能和高级话题。但值得注意的是,知识和工具只是起点。真正的技能和理解来自于实际的应用和实践。在探索网页自动化和数据抓取的世界时,请始终保持警惕,遵循最佳实践,并尊重法律和道德准则。祝您学习愉快,探索无尽!
因为爬虫这种技术,既不需要你系统地精通一门语言,也不需要多么高深的数据库技术。
我这里准备了详细的Python资料,除了为你提供一条清晰的学习路径,我甄选了最实用的学习资源以及庞大的实例库。短时间的学习,你就能够很好地掌握爬虫这个技能,获取你想得到的数据。
我们把Python的所有知识点,都穿插在了漫画里面。
在Python小课中,你可以通过漫画的方式学到知识点,难懂的专业知识瞬间变得有趣易懂。
你就像漫画的主人公一样,穿越在剧情中,通关过坎,不知不觉完成知识的学习。
这份完整版的Python全套学习资料已经上传CSDN,朋友们如果需要也可以扫描下方csdn官方二维码或者点击主页和文章下方的微信卡片获取领取方式,【保证100%免费】
文章浏览阅读1k次。通过使用ajax方法跨域请求是浏览器所不允许的,浏览器出于安全考虑是禁止的。警告信息如下:不过jQuery对跨域问题也有解决方案,使用jsonp的方式解决,方法如下:$.ajax({ async:false, url: 'http://www.mysite.com/demo.do', // 跨域URL ty..._nginx不停的xhr
文章浏览阅读2k次。关于在 Oracle 中配置 extproc 以访问 ST_Geometry,也就是我们所说的 使用空间SQL 的方法,官方文档链接如下。http://desktop.arcgis.com/zh-cn/arcmap/latest/manage-data/gdbs-in-oracle/configure-oracle-extproc.htm其实简单总结一下,主要就分为以下几个步骤。..._extproc
文章浏览阅读1.5w次。linux下没有上面的两个函数,需要使用函数 mbstowcs和wcstombsmbstowcs将多字节编码转换为宽字节编码wcstombs将宽字节编码转换为多字节编码这两个函数,转换过程中受到系统编码类型的影响,需要通过设置来设定转换前和转换后的编码类型。通过函数setlocale进行系统编码的设置。linux下输入命名locale -a查看系统支持的编码_linux c++ gbk->utf8
文章浏览阅读750次。今天准备从生产库向测试库进行数据导入,结果在imp导入的时候遇到“ IMP-00009:导出文件异常结束” 错误,google一下,发现可能有如下原因导致imp的数据太大,没有写buffer和commit两个数据库字符集不同从低版本exp的dmp文件,向高版本imp导出的dmp文件出错传输dmp文件时,文件损坏解决办法:imp时指定..._imp-00009导出文件异常结束
文章浏览阅读143次。当下是一个大数据的时代,各个行业都离不开数据的支持。因此,网络爬虫就应运而生。网络爬虫当下最为火热的是Python,Python开发爬虫相对简单,而且功能库相当完善,力压众多开发语言。本次教程我们爬取前程无忧的招聘信息来分析Python程序员需要掌握那些编程技术。首先在谷歌浏览器打开前程无忧的首页,按F12打开浏览器的开发者工具。浏览器开发者工具是用于捕捉网站的请求信息,通过分析请求信息可以了解请..._初级python程序员能力要求
文章浏览阅读7.6k次,点赞2次,收藏6次。@Service标注的bean,类名:ABDemoService查看源码后发现,原来是经过一个特殊处理:当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致public class AnnotationBeanNameGenerator implements BeanNameGenerator { private static final String C..._@service beanname
文章浏览阅读6.9w次,点赞73次,收藏463次。1.前序创建#include<stdio.h>#include<string.h>#include<stdlib.h>#include<malloc.h>#include<iostream>#include<stack>#include<queue>using namespace std;typed_二叉树的建立
文章浏览阅读7.1k次。在Asp.net上使用Excel导出功能,如果文件名出现中文,便会以乱码视之。 解决方法: fileName = HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8);_asp.net utf8 导出中文字符乱码
文章浏览阅读2.1k次,点赞4次,收藏23次。第一次实验 词法分析实验报告设计思想词法分析的主要任务是根据文法的词汇表以及对应约定的编码进行一定的识别,找出文件中所有的合法的单词,并给出一定的信息作为最后的结果,用于后续语法分析程序的使用;本实验针对 PL/0 语言 的文法、词汇表编写一个词法分析程序,对于每个单词根据词汇表输出: (单词种类, 单词的值) 二元对。词汇表:种别编码单词符号助记符0beginb..._对pl/0作以下修改扩充。增加单词
文章浏览阅读773次。我在使用adb.exe时遇到了麻烦.我想使用与bash相同的adb.exe shell提示符,所以我决定更改默认的bash二进制文件(当然二进制文件是交叉编译的,一切都很完美)更改bash二进制文件遵循以下顺序> adb remount> adb push bash / system / bin /> adb shell> cd / system / bin> chm..._adb shell mv 权限
文章浏览阅读6.8k次,点赞12次,收藏125次。1. 单目相机标定引言相机标定已经研究多年,标定的算法可以分为基于摄影测量的标定和自标定。其中,应用最为广泛的还是张正友标定法。这是一种简单灵活、高鲁棒性、低成本的相机标定算法。仅需要一台相机和一块平面标定板构建相机标定系统,在标定过程中,相机拍摄多个角度下(至少两个角度,推荐10~20个角度)的标定板图像(相机和标定板都可以移动),即可对相机的内外参数进行标定。下面介绍张氏标定法(以下也这么称呼)的原理。原理相机模型和单应矩阵相机标定,就是对相机的内外参数进行计算的过程,从而得到物体到图像的投影_相机-投影仪标定
文章浏览阅读2.2k次。文章目录Wayland 架构Wayland 渲染Wayland的 硬件支持简 述: 翻译一篇关于和 wayland 有关的技术文章, 其英文标题为Wayland Architecture .Wayland 架构若是想要更好的理解 Wayland 架构及其与 X (X11 or X Window System) 结构;一种很好的方法是将事件从输入设备就开始跟踪, 查看期间所有的屏幕上出现的变化。这就是我们现在对 X 的理解。 内核是从一个输入设备中获取一个事件,并通过 evdev 输入_wayland