【15】Selenium 爬取實戰

一、selenium適用場景

二、爬取目標

三、爬取列表頁

(1)初始化

(2)加載列表頁

(3)解析列表頁

(4)main

四、爬取詳情頁

(1)加載詳情頁

(2)解析詳情頁?

(3)修改main()

五、存儲數據

六、完整代碼


????????我們學習了 Selenium 的基本用法,【【14】Selenium的基本使用-CSDN博客】本節我們就來結合一個實際的案例來體會一下 Selenium 的適用場景以及使用方法。

一、selenium適用場景

????????在前面的實戰案例中,有的網頁我們可以直接用 requests 來爬取,有的可以直接通過分析 Ajax 來爬取,不同的網站類型有其適用的爬取方法。

????????Selenium 同樣也有其適用場景:對于那些帶有 JavaScript 渲染的網頁,①有些情況下我們可以直接用 requests 來模擬 Ajax 請求來直接得到數據。②有些情況下 Ajax 的一些請求接口可能帶有一些加密參數,如 token、sign 等等,如果不分析清楚這些參數是怎么生成的話,我們就難以模擬和構造這些參數。怎么辦呢?這時候我們可以直接選擇使用 Selenium 驅動瀏覽器渲染的方式來另辟蹊徑,實現所見即所得的爬取【相當于繞過了 Ajax 請求分析和模擬的階段,直達目標】

????????然而 Selenium 當然也有其局限性,它的爬取效率較低,有些爬取需要模擬瀏覽器的操作,實現相對煩瑣。不過在某些場景下也不失為一種有效的爬取手段。?

二、爬取目標

適用 Selenium 的站點來做案例,其鏈接為?https://spa2.scrape.center/?還是和之前一樣的電影網站,頁面如圖所示。

其 Ajax 請求接口和每部電影的 URL 都包含了加密參數,

比如我們點擊任意一部電影,觀察一下 URL 的變化,如圖所示:

????????這里我們可以看到詳情頁的 URL 和之前就不一樣了,在之前的案例中,URL 的 detail 后面本來直接跟的是 id,如 1、2、3 等數字,但是這里直接變成了一個長字符串,看似是一個 Base64 編碼的內容,所以這里我們無法直接根據規律構造詳情頁的 URL 了。?

????????好,那么接下來我們直接看看 Ajax 的請求,我們從列表頁的第 1 頁到第 10 頁依次點一下,觀察一下 Ajax 請求是怎樣的,如圖所示:

?????????可以看到這里接口的參數比之前多了一個 token,而且每次請求的 token 都是不同的,這個 token 同樣看似是一個 Base64 編碼的字符串。更困難的是,這個接口還是有時效性的,如果我們把 Ajax 接口 URL 直接復制下來,短期內是可以訪問的,但是過段時間之后就無法訪問了,會直接返回 401 狀態碼。

一段時間后:

?????????那現在怎么辦呢?之前我們可以直接用 requests 來構造 Ajax 請求,但現在 Ajax 請求接口帶了這個 token,而且還是可變的,現在我們也不知道 token 的生成邏輯,那就沒法直接通過構造 Ajax 請求的方式來爬取了。這時候我們可以把 token 的生成邏輯分析出來再模擬 Ajax 請求,但這種方式相對較難。所以這里我們可以直接用 Selenium 來繞過這個階段,直接獲取最終 JavaScript 渲染完成的頁面源碼,再提取數據就好了。

所以本課時我們要完成的目標有:

  • 通過 Selenium 遍歷列表頁,獲取每部電影的詳情頁 URL。
  • 通過 Selenium 根據上一步獲取的詳情頁 URL 爬取每部電影的詳情頁。
  • 提取每部電影的名稱、類別、分數、簡介、封面等內容。

三、爬取列表頁

(1)初始化

from selenium import webdriverfrom selenium.common.exceptions import TimeoutExceptionfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support import expected_conditions as ECfrom selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.chrome.service import Serviceimport logginglogging.basicConfig(level=logging.INFO,format='%(asctime)s - %(levelname)s: %(message)s')INDEX_URL = 'https://spa2.scrape.center/page/{page}'TIME_OUT = 10TOTAL_PAGE = 10
driver_path = "E:/chromedriver-win64/chromedriver.exe"
#
service = Service(driver_path)
browser = webdriver.Chrome(service=service)wait = WebDriverWait(browser, TIME_OUT)

????????首先我們導入了一些必要的 Selenium 模塊,包括 webdriver、WebDriverWait 等等,后面我們會用到它們來實現頁面的爬取和延遲等待等設置。然后接著定義了一些變量和日志配置,和之前幾課時的內容是類似的。接著我們使用 Chrome 類生成了一個 webdriver 對象,賦值為 browser,這里我們可以通過 browser 調用 Selenium 的一些 API 來完成一些瀏覽器的操作,如截圖、點擊、下拉等等。最后我們又聲明了一個 WebDriverWait 對象,利用它我們可以配置頁面加載的最長等待時間。

(2)加載列表頁

????????好,接下來我們就觀察下列表頁,實現列表頁的爬取吧。這里可以觀察到列表頁的 URL 還是有一定規律的,比如第一頁為?https://dynamic2.scrape.center/page/1,頁碼就是 URL 最后的數字,所以這里我們可以直接來構造每一頁的 URL。

?????????那么每個列表頁要怎么判斷是否加載成功了呢?很簡單,當頁面出現了我們想要的內容就代表加載成功了。在這里我們就可以用 Selenium 的隱式判斷條件來判定,比如每部電影的信息區塊的 CSS 選擇器為 #index .item,如圖所示。

????????所以這里我們直接使用 visibility_of_all_elements_located 判斷條件加上 CSS 選擇器的內容即可判定頁面有沒有加載出來,配合 WebDriverWait 的超時配置,我們就可以實現 10 秒的頁面的加載監聽。如果 10 秒之內,我們所配置的條件符合,則代表頁面加載成功,否則則會拋出 TimeoutException 異常。

代碼實現如下:

def?scrape_page(url,?condition,?locator):logging.info('scraping?%s',?url)try:browser.get(url)wait.until(condition(locator))except?TimeoutException:logging.error('error?occurred?while?scraping?%s',?url,?exc_info=True)def?scrape_index(page):url?=?INDEX_URL.format(page=page)scrape_page(url,?condition=EC.visibility_of_all_elements_located,locator=(By.CSS_SELECTOR,?'#index?.item'))

????????第一個方法 scrape_page 依然是一個通用的爬取方法,它可以實現任意 URL 的爬取和狀態監聽以及異常處理,它接收 url、condition、locator 三個參數,其中 url 參數就是要爬取的頁面 URL;condition 就是頁面加載的判定條件,它可以是 expected_conditions 的其中某一項判定條件,如 visibility_of_all_elements_located、visibility_of_element_located 等等;locator 代表定位器,是一個元組,它可以通過配置查詢條件和參數來獲取一個或多個節點,如 (By.CSS_SELECTOR, '#index .item') 則代表通過 CSS 選擇器查找 #index .item 來獲取列表頁所有電影信息節點。另外爬取的過程添加了 TimeoutException 檢測,如果在規定時間(這里為 10 秒)沒有加載出來對應的節點,那就拋出 TimeoutException 異常并輸出錯誤日志。

????????第二個方法 scrape_index 則是爬取列表頁的方法,它接收一個參數 page,通過調用 scrape_page 方法并傳入 condition 和 locator 對象,完成頁面的爬取。這里 condition 我們用的是 visibility_of_all_elements_located,代表所有的節點都加載出來才算成功。

注意,這里爬取頁面我們不需要返回任何結果,因為執行完 scrape_index 后,頁面正好處在對應的頁面加載完成的狀態,我們利用 browser 對象可以進一步進行信息的提取。

(3)解析列表頁

好,現在我們已經可以加載出來列表頁了,下一步當然就是進行列表頁的解析,提取出詳情頁 URL ,我們定義一個如下的解析列表頁的方法:

from urllib.parse import urljoindef parse_index():elements = browser.find_elements(By.CSS_SELECTOR, '#index .item .name')for element in elements:href = element.get_attribute('href')yield urljoin(INDEX_URL, href)

????????這里我們通過 find_elements_by_css_selector 方法直接提取了所有電影的名稱,接著遍歷結果,通過 get_attribute 方法提取了詳情頁的 href,再用 urljoin 方法合并成一個完整的 URL。?

(4)main

def?main():try:for?page?in?range(1,?TOTAL_PAGE?+?1):scrape_index(page)detail_urls?=?parse_index()logging.info('details?urls?%s',?list(detail_urls))finally:browser.close()

遍歷了所有頁碼,依次爬取了每一頁的列表頁并提取出來了詳情頁的 URL。?

觀察結果我們可以發現,詳情頁那一個個不規則的 URL 就成功被我們提取到了!

四、爬取詳情頁

????????好了,既然現在我們已經可以成功拿到詳情頁的 URL 了,接下來我們就進一步完成詳情頁的爬取并提取對應的信息吧。

(1)加載詳情頁

????????同樣的邏輯,詳情頁我們也可以加一個判定條件,如判斷電影名稱加載出來了就代表詳情頁加載成功,同樣調用 scrape_page 方法即可,代碼實現如下:

def?scrape_detail(url):scrape_page(url,?condition=EC.visibility_of_element_located,locator=(By.TAG_NAME,?'h2'))

????????這里的判定條件 condition 我們使用的是 visibility_of_element_located,即判斷單個元素出現即可,locator 我們傳入的是 (By.TAG_NAME, 'h2'),即 h2 這個節點,也就是電影的名稱對應的節點,如圖所示。

(2)解析詳情頁?

????????如果執行了 scrape_detail 方法,沒有出現 TimeoutException 的話,頁面就加載成功了,接著我們再定義一個解析詳情頁的方法,來提取出我們想要的信息就可以了,實現如下:

def parse_detail():url = browser.current_url# 使用新的定位方法name = browser.find_element(By.TAG_NAME, 'h2').text# 選擇所有類別并提取文本categories = [element.text for element in browser.find_elements(By.CSS_SELECTOR, '.categories button span')]# 獲取封面圖的 src 屬性cover = browser.find_element(By.CSS_SELECTOR, '.cover').get_attribute('src')# 獲取評分score = browser.find_element(By.CLASS_NAME, 'score').text# 獲取劇情簡介drama = browser.find_element(By.CSS_SELECTOR, '.drama p').textreturn {'url': url,'name': name,'categories': categories,'cover': cover,'score': score,'drama': drama}

?這里我們定義了一個 parse_detail 方法,提取了 URL、名稱、類別、封面、分數、簡介等內容,提取方式如下:

  • URL:直接調用 browser 對象的 current_url 屬性即可獲取當前頁面的 URL。

  • 名稱:通過提取 h2 節點內部的文本即可獲取,這里使用了 find_element_by_tag_name 方法并傳入 h2,提取到了名稱的節點,然后調用 text 屬性即提取了節點內部的文本,即電影名稱。

  • 類別:為了方便,類別我們可以通過 CSS 選擇器來提取,其對應的 CSS 選擇器為 .categories button span,可以選中多個類別節點,這里我們通過 find_elements_by_css_selector 即可提取 CSS 選擇器對應的多個類別節點,然后依次遍歷這個結果,調用它的 text 屬性獲取節點內部文本即可。

  • 封面:同樣可以使用 CSS 選擇器 .cover 直接獲取封面對應的節點,但是由于其封面的 URL 對應的是 src 這個屬性,所以這里用 get_attribute 方法并傳入 src 來提取。

  • 分數:分數對應的 CSS 選擇器為 .score ,我們可以用上面同樣的方式來提取,但是這里我們換了一個方法,叫作 find_element_by_class_name,它可以使用 class 的名稱來提取節點,能達到同樣的效果,不過這里傳入的參數就是 class 的名稱 score 而不是 .score 了。提取節點之后,我們再調用 text 屬性提取節點文本即可。

  • 簡介:同樣可以使用 CSS 選擇器 .drama p 直接獲取簡介對應的節點,然后調用 text 屬性提取文本即可。

最后,我們把結果構造成一個字典返回即可。

(3)修改main()

?在 main 方法中再添加這兩個方法的調用,實現如下:

def?main():try:for?page?in?range(1,?TOTAL_PAGE?+?1):scrape_index(page)detail_urls?=?parse_index()for?detail_url?in?list(detail_urls):logging.info('get?detail?url?%s',?detail_url)scrape_detail(detail_url)detail_data?=?parse_detail()logging.info('detail?data?%s',?detail_data)finally:browser.close()

這樣,爬取完列表頁之后,我們就可以依次爬取詳情頁,來提取每部電影的具體信息了。

2020-03-29?12:24:10,723?-?INFO:?scraping?https://dynamic2.scrape.center/page/12020-03-29?12:24:16,997?-?INFO:?get?detail?url?https://dynamic2.scrape.center/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIx2020-03-29?12:24:16,997?-?INFO:?scraping?https://dynamic2.scrape.center/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIx2020-03-29?12:24:19,289?-?INFO:?detail?data?{'url':?'https://dynamic2.scrape.center/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIx',?'name':?'霸王別姬?-?Farewell?My?Concubine',?'categories':?['劇情',?'愛情'],?'cover':?'https://p0.meituan.net/movie/ce4da3e03e655b5b88ed31b5cd7896cf62472.jpg@464w_644h_1e_1c',?'score':?'9.5',?'drama':?'影片借一出《霸王別姬》的京戲,牽扯出三個人之間一段隨時代風云變幻的愛恨情仇。段小樓(張豐毅?飾)與程蝶衣(張國榮?飾)是一對打小一起長大的師兄弟,兩人一個演生,一個飾旦,一向配合天衣無縫,尤其一出《霸王別姬》,更是譽滿京城,為此,兩人約定合演一輩子《霸王別姬》。但兩人對戲劇與人生關系的理解有本質不同,段小樓深知戲非人生,程蝶衣則是人戲不分。段小樓在認為該成家立業之時迎娶了名妓菊仙(鞏俐?飾),致使程蝶衣認定菊仙是可恥的第三者,使段小樓做了叛徒,自此,三人圍繞一出《霸王別姬》生出的愛恨情仇戰開始隨著時代風云的變遷不斷升級,終釀成悲劇。'}2020-03-29?12:24:19,291?-?INFO:?get?detail?url?https://dynamic2.scrape.center/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIy2020-03-29?12:24:19,291?-?INFO:?scraping?https://dynamic2.scrape.center/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIy2020-03-29?12:24:21,524?-?INFO:?detail?data?{'url':?'https://dynamic2.scrape.center/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIy',?'name':?'這個殺手不太冷?-?Léon',?'categories':?['劇情',?'動作',?'犯罪'],?'cover':?'https://p1.meituan.net/movie/6bea9af4524dfbd0b668eaa7e187c3df767253.jpg@464w_644h_1e_1c',?'score':?'9.5',?'drama':?'里昂(讓·雷諾?飾)是名孤獨的職業殺手,受人雇傭。一天,鄰居家小姑娘馬蒂爾德(納塔麗·波特曼?飾)敲開他的房門,要求在他那里暫避殺身之禍。原來鄰居家的主人是警方緝毒組的眼線,只因貪污了一小包毒品而遭惡警(加里·奧德曼?飾)殺害全家的懲罰。馬蒂爾德?得到里昂的留救,幸免于難,并留在里昂那里。里昂教小女孩使槍,她教里昂法文,兩人關系日趨親密,相處融洽。?女孩想著去報仇,反倒被抓,里昂及時趕到,將女孩救回。混雜著哀怨情仇的正邪之戰漸次升級,更大的沖突在所難免……'}...

五、存儲數據

保存為 JSON 文本文件,實現如下:

from?os?import?makedirs
import jsonfrom?os.path?import?existsRESULTS_DIR?=?'results'exists(RESULTS_DIR)?or?makedirs(RESULTS_DIR)def?save_data(data):name?=?data.get('name')data_path?=?f'{RESULTS_DIR}/{name}.json'json.dump(data,?open(data_path,?'w',?encoding='utf-8'),?ensure_ascii=False,?indent=2)

如果覺得爬取過程中彈出瀏覽器有所干擾,我們可以開啟 Chrome 的 Headless 模式,這樣爬取過程中便不會再彈出瀏覽器了,同時爬取速度還有進一步的提升。

只需要做如下修改即可:

options?=?webdriver.ChromeOptions()options.add_argument('--headless')browser?=?webdriver.Chrome(options=options)

?最后添加上 save_data 的調用,完整看下運行效果:

六、完整代碼

from selenium import webdriverfrom selenium.common.exceptions import TimeoutExceptionfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support import expected_conditions as ECfrom selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.chrome.service import Serviceimport logginglogging.basicConfig(level=logging.INFO,format='%(asctime)s - %(levelname)s: %(message)s')INDEX_URL = 'https://spa2.scrape.center/page/{page}'TIME_OUT = 10TOTAL_PAGE = 10
driver_path = "E:/chromedriver-win64/chromedriver.exe"
#
service = Service(driver_path)
browser = webdriver.Chrome(service=service)wait = WebDriverWait(browser, TIME_OUT)def scrape_page(url, condition, locator):logging.info('scraping %s', url)try:browser.get(url)wait.until(condition(locator))except TimeoutException:logging.error('error occurred while scraping %s', url, exc_info=True)def scrape_index(page):url = INDEX_URL.format(page=page)scrape_page(url, condition=EC.visibility_of_all_elements_located,locator=(By.CSS_SELECTOR, '#index .item'))
from urllib.parse import urljoindef parse_index():elements = browser.find_elements(By.CSS_SELECTOR, '#index .item .name')for element in elements:href = element.get_attribute('href')yield urljoin(INDEX_URL, href)def scrape_detail(url):scrape_page(url, condition=EC.visibility_of_element_located,locator=(By.TAG_NAME, 'h2'))
from selenium.webdriver.common.by import Bydef parse_detail():url = browser.current_url# 使用新的定位方法name = browser.find_element(By.TAG_NAME, 'h2').text# 選擇所有類別并提取文本categories = [element.text for element in browser.find_elements(By.CSS_SELECTOR, '.categories button span')]# 獲取封面圖的 src 屬性cover = browser.find_element(By.CSS_SELECTOR, '.cover').get_attribute('src')# 獲取評分score = browser.find_element(By.CLASS_NAME, 'score').text# 獲取劇情簡介drama = browser.find_element(By.CSS_SELECTOR, '.drama p').textreturn {'url': url,'name': name,'categories': categories,'cover': cover,'score': score,'drama': drama}
from os import makedirsfrom os.path import exists
import  jsonRESULTS_DIR = 'results'exists(RESULTS_DIR) or makedirs(RESULTS_DIR)def save_data(data):name = data.get('name')data_path = f'{RESULTS_DIR}/{name}.json'# 保存數據到JSON文件with open(data_path, 'w', encoding='utf-8') as file:json.dump(data, file, ensure_ascii=False, indent=2)def main():try:# 遍歷所有頁面for page in range(1, TOTAL_PAGE + 1):# 獲取并解析每頁的URLscrape_index(page)detail_urls = parse_index()# 遍歷詳情頁鏈接并解析詳情數據for detail_url in list(detail_urls):logging.info('get detail url %s', detail_url)# 獲取詳情頁面內容scrape_detail(detail_url)detail_data = parse_detail()# 日志打印詳情數據logging.info('detail data %s', detail_data)# 保存解析到的詳情數據save_data(detail_data)finally:# 關閉瀏覽器browser.close()if __name__ == "__main__":main()

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/75013.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/75013.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/75013.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何封裝一個上傳文件組件

#今天用el-upload感到很多不方便,遂決定自己封裝一個。注:本文不提供表面的按鈕樣式和文件上傳成功后的樣式,需要自己創建。本文僅介紹邏輯函數# 1,準備幾個表面用來指引上傳的元素 2,創造統一的隱藏文件上傳輸入框&…

【計網】數據包

期末復習自用的,處理得比較草率,復習的同學或者想看基礎的同學可以看看,大佬的話可以不用浪費時間在我的水文上了 1.數據包的定義: 數據包是網絡通信中的基本單元,它包含了通過網絡傳輸的所有必要信息。數據包的結構…

HTTP抓包Websocket抓包(Fiddler)

近期時常要和各個廠商的java云平臺打交道:登錄、上傳、下載等,程序的日志雖必不可少,但前期調試階段,免不了遇到問題,這時有一個稱手的抓包工具就顯得尤為重要了。 Fiddler Everywhere是一款跨平臺的網絡調試工具&…

Git和GitCode使用(從Git安裝到上傳項目一條龍)

第一步 菜鳥教程-Git教程 點擊上方鏈接,完成Git的安裝,并了解Git 工作流程,知道Git 工作區、暫存區和版本庫的區別 第二步 GitCode官方幫助文檔-SSH 公鑰管理 點擊上方鏈接,完成SSH公鑰設置 第三步(GitCode的官方引…

基于 WebAssembly 的 Game of Life 交互實現

一、前言 在前期的實現中,我們使用 Rust 編寫核心邏輯,并通過 WebAssembly 將其引入到 Web 環境中,再利用 JavaScript 進行渲染。接下來,我們將在這一基礎上增加用戶交互功能,使模擬過程不僅能夠自動演化,…

【keil】單步調試

一、步驟 1、打開stc-isp軟件 2.打開keil仿真設置,選擇對應的單片機型號 3.點擊將所選目標單片機設置為仿真芯片,點擊下載,按一下單片機打下載按鈕 4.此時已經將仿真程序下載到單片機 5.此時點擊options,找到debug選擇STC Montor 51 Driv…

c++弱指針實現原理

在 C 中,弱指針(std::weak_ptr)是一種特殊的智能指針,其核心目標是?解決 std::shared_ptr 的循環引用問題?,同時不增加對象的引用計數。它的實現原理基于與 std::shared_ptr 共享的 ?控制塊(Control Blo…

【ManiSkill】環境success條件和reward函數學習筆記

1. “PickCube-v1” info["success"]:用于指示任務是否成功完成 布爾型張量,在環境的evaluate()方法中計算并返回: "success": is_obj_placed & is_robot_static這確保了機器人不僅能將物體準確放置在目標位置&am…

用空閑時間做了一個小程序-二維碼生成器

一直在摸魚中賺錢的大家好呀~ 先向各位魚友們匯報一下情況,目前小程序已經有900的魚友注冊使用過。雖然每天都有新的魚友注冊,但是魚友增長的還很緩慢。自從國慶前的文字轉語音的工具上線到現在已經將近有1個月沒有更新小程序了。但是今天終終終終終于又…

31天Python入門——第14天:異常處理

你好,我是安然無虞。 文章目錄 異常處理1. Python異常2. 異常捕獲try-except語句捕獲所有的異常信息獲取異常對象finally塊 3. raise語句4. 自定義異常5. 函數調用里面產生的異常補充練習 異常處理 1. Python異常 Python異常指的是在程序執行過程中發生的錯誤或異…

PyQt6實例_批量下載pdf工具_使用pyinstaller與installForge打包成exe文件

目錄 前置: 步驟: step one 準備好已開發完畢的項目代碼 step two 安裝pyinstaller step three 執行pyinstaller pdfdownload.py,獲取初始.spec文件 step four 修改.spec文件,將data文件夾加入到打包程序中 step five 增加…

Axure項目實戰:智慧城市APP(完整交互匯總版)

親愛的小伙伴,在您瀏覽之前,煩請關注一下,在此深表感謝! 課程主題:智慧城市APP 主要內容:主功能(社保查詢、醫療信息、公交查詢等)、活動、消息、我的頁面匯總 應用場景&#xff…

Appium Inspector使用教程

1.下載最新版本 https://github.com/appium/appium-inspector/releases 2.本地啟動一個Appium服務 若Android SDK已安裝Appium服務,則在任意terminal使用appium啟動服務即可 3.Appium Inspector客戶端配置連接到Appium服務 Configuring and Starting a Session…

Pycharm(七):幾個簡單案例

一.剪刀石頭布 需求:和電腦玩剪刀石頭布游戲 考察點:1.隨機數;2.判斷語句 import random # numrandom.randint(1,3) # print(num) # print(**30) #1.錄入玩家手勢 playerint(input(請輸入手勢:(1.剪刀 2.石頭 3&…

Python Cookbook-4.13 獲取字典的一個子集

任務 你有一個巨大的字典,字典中的一些鍵屬于一個特定的集合,而你想創建一個包含這個鍵集合及其對應值的新字典。 解決方案 如果你不想改動原字典: def sub_dict(somedict,somekeys,default None):return dict([(k, somedict.get(k,default)) for k…

VMware Ubuntu 網絡配置全攻略:從斷網到暢通無阻

一、網絡連接模式選擇(先搞懂原理) VMware提供三種網絡模式,就像手機的不同網絡套餐: 模式適用場景特點類比NAT個人上網/新手首選虛擬機共享主機IP,能上網但隱身家用WiFi橋接服務器/需要被局域網訪問虛擬機會獲得獨立…

鏈表(C++)

這是本人第二次學習鏈表,第一次學習鏈表是在大一上的C語言課上,首次接觸,感到有些難;第二次是在大一下學習數據結構時(就是這次),使用C再次理解鏈表。同時,這也是開啟數據結構學習寫…

【SPP】藍牙串口協議應用層深度解析:從連接建立到實戰開發

目錄 一、SPP應用層協議框架與角色模型 1.1 分層協議棧模型 1.2 設備角色模型(DevA 與 DevB 交互) 二、連接建立流程:從 SDP 到 RFCOMM 2.1 服務發現(SDP)流程(SDP 記錄關鍵參數) 2.2 連接…

Giteki 認證:無線產品進入日本市場的關鍵保障

目錄 適用產品認證范圍 認證項目及技術要求 認證流程 認證周期 與其他認證的對比 常見問題 注意事項 Giteki 認證,其名稱來源于日本語 “技適マーク”,羅馬字拼寫為 “GITEKI” ,在行業內也常被稱為 Telec 認證、MIC 認證、RF 認證或技…

Ubuntu24.04 配置遠程桌面服務

一:安裝 sudo apt update sudo apt install vino 二:設置 gsettings set org.gnome.Vino require-encryption false # 關閉加密(某些 VNC 客戶端不支持加密) gsettings set org.gnome.Vino prompt-enabled false # 關閉連接…