<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      網(wǎng)絡(luò)爬蟲開發(fā)

      爬取思路: 爬取網(wǎng)頁(yè)數(shù)據(jù)首先需要請(qǐng)求網(wǎng)站響應(yīng),需要安裝requests庫(kù),讀取網(wǎng)頁(yè)內(nèi)容需要安裝xml庫(kù),調(diào)用xml庫(kù)中的etree模塊來(lái)處理XmlHtml數(shù)據(jù),再使用Xpath解析數(shù)據(jù).

      掌握 XPath 后,你可以高效地從網(wǎng)頁(yè)或 XML 數(shù)據(jù)中提取所需信息,是爬蟲開發(fā)和數(shù)據(jù)處理的必備技能。

      需要學(xué)習(xí)和安裝的庫(kù)和框架也比較多,一個(gè)個(gè)的學(xué),做案例積累經(jīng)驗(yàn):

      pip install requests lxml beautifulsoup4 selenium pandas matplotlib fake_useragent tqdm openpyxl

      初識(shí)爬蟲

      1.requests請(qǐng)求庫(kù)模塊

      Pycharm終端安裝requests請(qǐng)求庫(kù)

      pip install requests

      ①.導(dǎo)入requests請(qǐng)求庫(kù)

      import requests

      ②.定義個(gè)變量要抓取的頁(yè)面:

      url = '網(wǎng)址'

      ③.構(gòu)造請(qǐng)求頭(偽裝身份user-agent)

      打開要抓取的網(wǎng)址,快捷鍵:F12→Network(網(wǎng)絡(luò))→Name(名稱)→點(diǎn)一個(gè)文件→Header(標(biāo)頭)→user-agent(拉到底部就會(huì)看到)

      #偽裝成瀏覽器的身份進(jìn)行抓取
      headers = {
          'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36'
      }

      ④.發(fā)起請(qǐng)求并接收響應(yīng)對(duì)象

      response = requests.get(url = url, headers = headers)
      encoding = 'utf-8'
      bd_url = 'https://www.baidu.com/'  # 定義要請(qǐng)求的url數(shù)據(jù)包
      response = requests.get(url=bd_url)  # 發(fā)起請(qǐng)求并且接收響應(yīng)對(duì)象
      response.encoding = 'utf-8'  # 設(shè)置編碼格式
      print(response)  # <Response [200]>  響應(yīng)對(duì)象
      print(response.text)  # 獲取文本內(nèi)容
      print(response.content)  # 獲取到進(jìn)制格式的數(shù)據(jù)
      print(response.headers)  # 獲取響應(yīng)頭信息
      print(response.request.headers)  # 獲取請(qǐng)求頭信息
      print(response.status_code)  # 獲取狀態(tài)碼
      print(response.encoding)  # 獲取當(dāng)前編碼格式
      print(response.url)  # 獲取到當(dāng)前請(qǐng)求的url
      print(response.cookies)  # 獲取到用戶身份對(duì)象
      print(response.content.decode())  # .decode() 默認(rèn)utf-8 進(jìn)行解碼 如果需要使用其他編碼進(jìn)行解碼 傳參即可

      ⑤.保存文件然后讀取

      #完整示例-爬圖
      import requests
      
      url = 'https://pic.netbian.com/uploads/allimg/240924/081942-17271371826661.jpg'
      response = requests.get(url=url)
      # print(response.content)
      with open('王楚然.jpg', 'wb') as f:
          f.write(response.content)
      #完整示例-爬音頻
      import requests
      
      url = 'https://m701.music.126.net/20240924221116/8ec6067b2ae956d58df4deff0bdddaf9/jdyyaac/obj/w5rDlsOJwrLDjj7CmsOj/31433228192/7100/62f1/fd29/3833d333ff983ce8eebe35872a9484ee.m4a'
      response = requests.get(url=url)
      with open('大人中.mp3', 'wb') as f:
          f.write(response.content)
      #爬視頻
      import requests
      
      cookies = {
          'PEAR_UUID': '7b913605-1037-4a28-b16a-46e7657e6f03',
          'Hm_lvt_9707bc8d5f6bba210e7218b8496f076a': '1727185861',
          'HMACCOUNT': '33EE743B756BCDEE',
          'Hm_lpvt_9707bc8d5f6bba210e7218b8496f076a': '1727185870',
      }
      
      headers = {
          'accept': '*/*',
          'accept-language': 'zh-CN,zh;q=0.9',
          'cache-control': 'no-cache',
          # 'cookie': 'PEAR_UUID=7b913605-1037-4a28-b16a-46e7657e6f03; Hm_lvt_9707bc8d5f6bba210e7218b8496f076a=1727185861; HMACCOUNT=33EE743B756BCDEE; Hm_lpvt_9707bc8d5f6bba210e7218b8496f076a=1727185870',
          'pragma': 'no-cache',
          'priority': 'i',
          'range': 'bytes=0-',
          'referer': 'https://www.pearvideo.com/',
          'sec-ch-ua': '"Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129"',
          'sec-ch-ua-mobile': '?0',
          'sec-ch-ua-platform': '"Windows"',
          'sec-fetch-dest': 'video',
          'sec-fetch-mode': 'no-cors',
          'sec-fetch-site': 'same-site',
          'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36',
      }
      
      response = requests.get(
          'https://video.pearvideo.com/mp4/short/20171004/cont-1165391-10964201-hd.mp4',
          cookies=cookies,
          headers=headers,
      )
      print(response.content)
      with open('1.mp4', 'wb') as f:
          f.write(response.content)

      Pycharm內(nèi)置模塊方法(不推薦使用)

      from urllib.request import urlopen
      url ='url'#要爬取的數(shù)據(jù)網(wǎng)頁(yè)
      html = urlopen(url)
      #print(html.read().decode('utf-8'))
      with open("爬取的文件.html", "w",encoding="utf-8") as f:
      write = f.write(html.read().decode('utf-8'))

      ★用input方法的get請(qǐng)求

      import requests
      from urllib.parse import quote
      import time
      
      try:
          # 獲取用戶輸入并進(jìn)行URL編碼
          content = input("請(qǐng)輸入你要查詢的內(nèi)容:")
          encoded_content = quote(content)
      
          # 構(gòu)建請(qǐng)求URL
          url = f"https://www.sogou.com/web?query={encoded_content}"
      
          # 設(shè)置請(qǐng)求頭模擬瀏覽器
          headers = {
              "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36"
          }
      
          # 發(fā)送HTTP請(qǐng)求
          print(f"正在請(qǐng)求: {url}")
          resp = requests.get(url, headers=headers, timeout=10)  # 設(shè)置超時(shí)時(shí)間
      
          # 檢查響應(yīng)狀態(tài)碼
          resp.raise_for_status()  # 若狀態(tài)碼非200,拋出HTTPError
      
          # 保存響應(yīng)內(nèi)容到文件
          filename = f"爬取的{content[:10]}內(nèi)容.html"  # 文件名包含部分查詢內(nèi)容
          with open(filename, "w", encoding="utf-8") as f:
              f.write(resp.text)  # 直接使用resp.text
      
          print(f"? 文件已成功保存為: {filename}")
          print(f"狀態(tài)碼: {resp.status_code}")
      
      except requests.exceptions.HTTPError as e:
          print(f"HTTP請(qǐng)求錯(cuò)誤: {e}")
      except requests.exceptions.Timeout:
          print("請(qǐng)求超時(shí),請(qǐng)重試")
      except requests.exceptions.RequestException as e:
          print(f"網(wǎng)絡(luò)請(qǐng)求異常: {e}")
      except Exception as e:
          print(f"發(fā)生未知錯(cuò)誤: {e}")
      finally:
          # 控制請(qǐng)求頻率
          time.sleep(1)  # 等待1秒后結(jié)束程序

      用input方法的post請(qǐng)求

      import requests
      from urllib.parse import urlencode
      import time
      import json
      
      try:
          # 獲取用戶輸入
          keyword = input("請(qǐng)輸入你要翻譯的內(nèi)容:")
      
          # 百度翻譯API的POST接口
          url = "https://fanyi.baidu.com/sug"
      
          # 設(shè)置請(qǐng)求頭
          headers = {
              "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
              "Content-Type": "application/x-www-form-urlencoded"
          }
      
          # 構(gòu)建POST請(qǐng)求的表單數(shù)據(jù)(百度翻譯API需要的參數(shù))
          data = {
              "kw": keyword  # 百度翻譯API使用'kw'參數(shù)傳遞要翻譯的內(nèi)容
          }
      
          # 發(fā)送POST請(qǐng)求
          print(f"正在請(qǐng)求: {url}")
          resp = requests.post(url, headers=headers, data=data, timeout=10) #發(fā)送post請(qǐng)求時(shí),傳參數(shù)用的是data.
      
          # 檢查響應(yīng)狀態(tài)碼
          resp.raise_for_status()
      
          # 解析JSON響應(yīng)
          result = resp.json()
      
          # 保存響應(yīng)內(nèi)容到文件
          filename = f"翻譯結(jié)果_{keyword[:10]}.json"
          with open(filename, "w", encoding="utf-8") as f:
              json.dump(result, f, ensure_ascii=False, indent=2)
      
          print(f"? 翻譯結(jié)果已保存為: {filename}")
          print(f"狀態(tài)碼: {resp.status_code}")
      
          # 簡(jiǎn)單打印翻譯結(jié)果
          if result.get('errno') == 0 and 'data' in result:
              print("\n翻譯結(jié)果預(yù)覽:")
              for item in result['data'][:3]:  # 只顯示前3個(gè)結(jié)果
                  print(f"{item.get('k', '')} -> {item.get('v', '')}")
      
      except requests.exceptions.HTTPError as e:
          print(f"HTTP請(qǐng)求錯(cuò)誤: {e}")
      except requests.exceptions.Timeout:
          print("請(qǐng)求超時(shí),請(qǐng)重試")
      except requests.exceptions.RequestException as e:
          print(f"網(wǎng)絡(luò)請(qǐng)求異常: {e}")
      except json.JSONDecodeError:
          print("無(wú)法解析JSON響應(yīng),可能是請(qǐng)求格式不正確")
      except Exception as e:
          print(f"發(fā)生未知錯(cuò)誤: {e}")
      finally:
          # 控制請(qǐng)求頻率
          time.sleep(1)

      參數(shù)請(qǐng)求與Cookie

       

      import requests
      url = "https://movie.douban.com/j/chart/top_list" #問(wèn)號(hào)后面的參數(shù)可以用字典的形式傳參數(shù)
      
      data = {
          "type":"13",
          "interval_id":"100:90",
          "action": "",
          "start":"0",
          "limit":"20"
      }
      headers = {
          "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
              "Content-Type": "application/x-www-form-urlencoded"
      }
      response = requests.get(url, params=data, headers=headers)#發(fā)送get請(qǐng)求時(shí),傳參數(shù)用的是params
      print(response.json())

      2.xpath數(shù)據(jù)解析(XML Path Language):是一種用于在 XML 或 HTML 文檔中定位節(jié)點(diǎn)的查詢語(yǔ)言和選擇特定元素的表達(dá)式語(yǔ)言。它就像是一個(gè)路徑導(dǎo)航系統(tǒng),能幫助開發(fā)者快速準(zhǔn)確地找到文檔中的特定節(jié)點(diǎn)或節(jié)點(diǎn)集合。在網(wǎng)頁(yè)數(shù)據(jù)抓取、XML 處理等場(chǎng)景中廣泛應(yīng)用。

      作用

      • 數(shù)據(jù)提取:在網(wǎng)頁(yè)爬蟲中,當(dāng)需要從復(fù)雜的 HTML 頁(yè)面結(jié)構(gòu)中提取特定信息,如標(biāo)題、正文、鏈接等時(shí),XPath 可以精確定位到包含這些信息的 HTML 元素,然后方便地提取出所需數(shù)據(jù)。
      • 元素定位:在自動(dòng)化測(cè)試中,需要操作網(wǎng)頁(yè)上的各種元素,如點(diǎn)擊按鈕、填寫表單等。XPath 可以幫助找到這些元素在頁(yè)面中的位置,從而實(shí)現(xiàn)對(duì)它們的操作。

      在編程語(yǔ)言中使用 XPath

      pycharm終端安裝lxml庫(kù):

      pip install lxml
      #或使用鏡像下載安裝
      pip install lxml -i 鏡像地址

      pycharm終端查看當(dāng)前環(huán)境下安裝了哪些庫(kù)

      pip list

      2.1.etree通常指的是lxml庫(kù)的etree模塊(ElementTree),它是 Python 中處理 XML 和 HTML 文檔的強(qiáng)大工具。如果沒(méi)有安裝lxmlPython 標(biāo)準(zhǔn)庫(kù)中也有一個(gè)功能類似的xml.etree.ElementTree模塊,但lxml更高效且支持更多特性

      主要功能

        • 解析 XML/HTML 文檔:可以從字符串、文件或 URL 加載 XML/HTML 內(nèi)容。
        • 構(gòu)建文檔:支持動(dòng)態(tài)創(chuàng)建 XML/HTML 結(jié)構(gòu)。
        • 元素操作:提供簡(jiǎn)潔的 API 來(lái)遍歷、修改和查詢文檔節(jié)點(diǎn)。
        • XPath 支持:通過(guò) XPath 表達(dá)式高效定位特定元素。

      ①.解析 XML 文檔

      2.2.etree.fromstring():可以將 XML/HTML 格式的字符串解析為樹形結(jié)構(gòu)(ElementTree 對(duì)象),以便于后續(xù)的遍歷、查詢和修改。

      from lxml import etree
      
      xml_str = '<book><title>Python編程</title><price>99.0</price></book>'
      root = etree.fromstring(xml_str)
      
      # 獲取根節(jié)點(diǎn)標(biāo)簽
      print(root.tag)  # 輸出: book
      
      # 查找子節(jié)點(diǎn)
      title = root.find('title').text
      price = root.find('price').text
      print(f"書名: {title}, 價(jià)格: {price}")  # 輸出: 書名: Python編程, 價(jià)格: 99.0

      ②.遍歷元素

      # 遍歷所有子元素
      for child in root:
          print(child.tag, child.text)  # 輸出: element 內(nèi)容
      
      # 使用XPath查找元素
      elements = root.xpath('//element')

      ③.修改文檔

      # 創(chuàng)建新元素
      new_element = etree.Element('new_element')
      new_element.text = '新內(nèi)容'
      
      # 添加到根節(jié)點(diǎn)
      root.append(new_element)
      
      # 修改現(xiàn)有元素
      root.find('element').text = '更新后的內(nèi)容'
      
      # 刪除元素
      root.remove(new_element)

      ④.輸出文檔

      # 轉(zhuǎn)換為字符串
      xml_output = etree.tostring(root, pretty_print=True, encoding='unicode')
      print(xml_output)
      
      # 寫入文件
      # etree.ElementTree(root).write('output.xml', pretty_print=True)

      Python(使用lxml庫(kù))從lxml庫(kù)中導(dǎo)入etree

      from lxml import etree
      #如果Pycharm報(bào)錯(cuò)可以考慮下面這種導(dǎo)入方式
      from lxml imprt html
      etree=html.etree
      html = '<html><body><div class="content"><h1>Hello</h1></div></body></html>' tree = etree.HTML(html) # 選擇所有<h1>元素的文本 titles = tree.xpath('//h1/text()') print(titles) # 輸出: ['Hello'] # 選擇class為"content"的<div>元素 divs = tree.xpath('//div[@class="content"]')

      打開抓取的html文檔然后讀取

      with open('抓取的文檔.html', 'r', encoding='utf-8') as f:
          html = f.read()  # 讀取
      # print(html)  # 讀取出來(lái)的文本內(nèi)容
      # print(type(html))  # <class 'str'>查看類開,字符串類型
      tree = etree.HTML(html)  # 渲染html

      JavaScript(瀏覽器環(huán)境)

      // 選擇第一個(gè)<h1>元素
      const h1 = document.evaluate('//h1', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
      
      // 選擇所有<a>元素的href屬性
      const links = document.evaluate('//a/@href', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
      for (let i = 0; i < links.snapshotLength; i++) {
        console.log(links.snapshotItem(i).value);
      }

      ①.基本路徑表達(dá)式

      xpath 通過(guò)路徑表達(dá)式從根節(jié)點(diǎn)/或當(dāng)前節(jié)點(diǎn).開始定位元素:

      xpath方法返回值是列表  xpath語(yǔ)法規(guī)定索引值從1開始

      • 絕對(duì)路徑:從根節(jié)點(diǎn)開始,使用 / 分隔節(jié)點(diǎn)名稱。
      xpath('/html/body/div/h1/')  # 選擇HTML文檔中的<h1>元素
      xpath('/html/body/div/h1/text()')  # 選擇HTML文檔中的<h1>元素的數(shù)據(jù)
      • 相對(duì)路徑從當(dāng)前節(jié)點(diǎn)開始,使用 // 表示任意層級(jí)的子節(jié)點(diǎn)。
      xpath('//div/p')  # 選擇所有<div>下的<p>元素(不限層級(jí))

      ②. 節(jié)點(diǎn)選擇器

      符號(hào) 作用
      // 從任意位置開始選擇節(jié)點(diǎn)。
      . 選擇當(dāng)前節(jié)點(diǎn)。
      .. 選擇當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)。
      @ 選擇屬性。
      * 通配符,匹配任意節(jié)點(diǎn)或?qū)傩?/td>
      [ ] 條件表達(dá)式,用于篩選節(jié)點(diǎn)。
      position 當(dāng)前節(jié)點(diǎn)的位置(如 [1] 表示第一個(gè)匹配的節(jié)點(diǎn))。

      ③.常用函數(shù)

      • 文本匹配:
      xpath('//div[text()="Hello World"]')  # 選擇文本內(nèi)容為"Hello World"的<div>
      xpath('//div[contains(text(), "World")]')  # 選擇包含"World"的<div>

      屬性匹配:

      xpath('//a[@) # 選擇href屬性為指定值的<a>標(biāo)簽
      xpath('//input[@type="text"]') # 選擇包含"World"的<div>

      位置篩選:

      xpath('//li[position()=1]') # 選擇第一個(gè)<li> 
      xpath('//li[last()]') # 選擇最后一個(gè)<li>.<li>

      ④.邏輯運(yùn)算符

      使用 andornot() 組合條件:

      xpath('//div[@class="container" and @id="main"]') # 同時(shí)滿足兩個(gè)屬性條件
      xpath('//div[@class="item" or @class="product"] ') # 滿足任一屬性條件
      xpath('//div[not(@class="ignore")]') # 排除特定屬性的<div>

      ⑤.軸(Axes)選擇

      軸用于選擇當(dāng)前節(jié)點(diǎn)的相關(guān)節(jié)點(diǎn)(如父節(jié)點(diǎn)、兄弟節(jié)點(diǎn)等):

      軸名稱 作用 示例
      parent:: 父節(jié)點(diǎn) xpath('//h1/parent::div')
      child:: 子節(jié)點(diǎn)(默認(rèn)) xpath('//div/child::p')
      descendant 所有后代節(jié)點(diǎn)(不限層級(jí)) xpath('//div/descendant::span')
      ancestor:: 所有祖先節(jié)點(diǎn)(包括父節(jié)點(diǎn)的父節(jié)點(diǎn)) xpath('//p/ancestor::body')
      following-sibling:: 后續(xù)兄弟節(jié)點(diǎn) xpath('//li[1]/following-sibling::li')
      preceding-sibling: 前續(xù)兄弟節(jié)點(diǎn) xpath('//li[3]/preceding-sibling::li')

      案例:

      # 導(dǎo)入所需庫(kù)
      import requests # 用于發(fā)送HTTP請(qǐng)求,獲取網(wǎng)頁(yè)內(nèi)容
      from lxml import etree # 用于解析HTML文檔,提取需要的信息
      
      # 定義基本參數(shù)
      # 目標(biāo)網(wǎng)頁(yè)URL(小說(shuō)章節(jié)頁(yè)面)
      url = 'https://www.xs386.com/6661/32866513.html'
      
      # 請(qǐng)求頭信息,模擬瀏覽器訪問(wèn)
      headers = {
          'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36'
      } # user-agent用于告訴服務(wù)器訪問(wèn)者的瀏覽器信息,避免被服務(wù)器識(shí)別為爬蟲而拒絕訪問(wèn)。
      
      # 發(fā)送GET請(qǐng)求獲取網(wǎng)頁(yè)內(nèi)容
      response = requests.get(url=url, headers=headers)
      
      # 設(shè)置正確的編碼,設(shè)置編碼為utf-8,確保中文顯示正常
      response.encoding = 'utf-8'
      
      # 將HTML文本解析為可操作的元素樹對(duì)象
      e = etree.HTML(response.text) # 將網(wǎng)頁(yè)源代碼轉(zhuǎn)換為解析樹,便于后續(xù)提取數(shù)據(jù)
      
      # 使用XPath表達(dá)式提取id為"content"的div內(nèi)的所有文本,注意返回的是列表
      content_list = e.xpath('//div[@id="content"]//text()') # 查找整個(gè)文檔中 id 屬性為 "content" 的 div 元素并提取該 div 下所有層級(jí)的文本內(nèi)容
      
      # 判斷是否成功提取到內(nèi)容
      if content_list:
      
          # 將列表內(nèi)容合并為字符串
          content = '\n'.join(content_list)
      
          # 清理內(nèi)容中的多余空格和換行
          content = content.strip()
          
          # 保存到文件(使用utf-8編碼)
          with open('上門龍婿.txt', 'w', encoding='utf-8') as f:
              f.write(content)
          print("內(nèi)容保存成功")
      else:
          print("未找到指定內(nèi)容")

       

      3.JSON(JavaScript Object Notation)是一種輕量級(jí)的數(shù)據(jù)交換格式,以易于人閱讀和編寫的文本格式存儲(chǔ)和表示數(shù)據(jù),同時(shí)也易于機(jī)器解析和生成,在前后端數(shù)據(jù)交互、配置文件等場(chǎng)景中被廣泛使用。

      一、JSON 的核心特點(diǎn)

      • 輕量級(jí):相比 XML 等格式,JSON 的數(shù)據(jù)結(jié)構(gòu)更簡(jiǎn)潔,文件體積更小,傳輸效率更高。
      • 跨語(yǔ)言兼容:幾乎所有編程語(yǔ)言都支持 JSON 的解析和生成,便于不同系統(tǒng)間的數(shù)據(jù)交互。
      • 可讀性強(qiáng):采用鍵值對(duì)(key-value)結(jié)構(gòu),格式清晰,易于理解和維護(hù)。
      • 結(jié)構(gòu)靈活:支持嵌套對(duì)象和數(shù)組,能表示復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。

      二、JSON 的基本語(yǔ)法規(guī)則

      數(shù)據(jù)類型與表示

      • 對(duì)象(Object):{}包裹,由鍵值對(duì)組成,鍵和值用:分隔,多個(gè)鍵值對(duì)用,分隔。
      • 數(shù)組(Array):[]包裹,元素可以是任意數(shù)據(jù)類型,元素間用,分隔。
      • 鍵值對(duì):鍵必須是字符串,值可以是字符串、數(shù)字、布爾值、null、對(duì)象或數(shù)組。
      {
        "id": 1001,
        "hobbies": ["閱讀", "編程"],
        "isStudent": false,
        "address": null
      }

      格式要求

      • 鍵名必須用雙引號(hào)""包裹(部分語(yǔ)言支持單引號(hào),但標(biāo)準(zhǔn) JSON 要求雙引號(hào))。
      • 逗號(hào)分隔時(shí),最后一個(gè)鍵值對(duì)后不能有多余的逗號(hào)(部分環(huán)境支持,但可能導(dǎo)致兼容性問(wèn)題)。

      三、JSON 與 JavaScript 的關(guān)系

      • 起源:JSON 最初是 JavaScript 的子集,但現(xiàn)在已獨(dú)立為跨語(yǔ)言的標(biāo)準(zhǔn)格式。
      • 在 JavaScript 中的使用:
        • 可以直接通過(guò)JSON.parse()將 JSON 字符串轉(zhuǎn)換為 JavaScript 對(duì)象。
        • 通過(guò)JSON.stringify()將 JavaScript 對(duì)象轉(zhuǎn)換為 JSON 字符串。
      // 示例:JSON與JavaScript對(duì)象的轉(zhuǎn)換
      const jsonStr = '{"name":"張三","age":25}';
      const obj = JSON.parse(jsonStr); // 轉(zhuǎn)換為對(duì)象
      console.log(obj.name); // 輸出:張三
      
      const data = { city: "北京", population: 2100 };
      const jsonData = JSON.stringify(data); // 轉(zhuǎn)換為JSON字符串
      console.log(jsonData); // 輸出:{"city":"北京","population":2100}

      四、JSON 的應(yīng)用場(chǎng)景

      • 前后端數(shù)據(jù)交互:Web 應(yīng)用中,前端通過(guò) API 請(qǐng)求從服務(wù)器獲取 JSON 數(shù)據(jù),或向服務(wù)器發(fā)送 JSON 格式的請(qǐng)求參數(shù)。
      • 配置文件:如項(xiàng)目配置文件(package.json)、系統(tǒng)配置等,用 JSON 存儲(chǔ)結(jié)構(gòu)化配置信息。
      • 數(shù)據(jù)存儲(chǔ):NoSQL 數(shù)據(jù)庫(kù)(如 MongoDB)支持 JSON 格式的文檔存儲(chǔ),部分關(guān)系型數(shù)據(jù)庫(kù)也支持 JSON 字段。
      • API 接口規(guī)范:RESTful API 通常以 JSON 作為數(shù)據(jù)交換格式,例如 OpenAPI(Swagger)規(guī)范。

      3.1.json.dump():用于將 Python 對(duì)象(如字典、列表)轉(zhuǎn)換為 JSON 格式的字符串,并將其寫入文件或類文件對(duì)象(如網(wǎng)絡(luò)連接、內(nèi)存緩沖區(qū)等)。這一過(guò)程也被稱為序列化(Serialization)

      json.dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, 
                allow_nan=True, cls=None, indent=None, separators=None, 
                default=None, sort_keys=False, **kw)

      參數(shù)說(shuō)明:

      • obj需要序列化的 Python 對(duì)象(如字典、列表)。
      • fp文件對(duì)象(如open('data.json', 'w')返回的對(duì)象),用于寫入 JSON 數(shù)據(jù)。
      • indent可選參數(shù),指定縮進(jìn)空格數(shù),用于美化 JSON 格式(如indent=2)。
      • ensure_ascii是否確保所有非 ASCII 字符被轉(zhuǎn)義(默認(rèn)True,中文會(huì)被轉(zhuǎn)義為\uXXXX)。
      • sort_keys是否按字典鍵排序(默認(rèn)False)。
      import json
      
      data = {
          "name": "張三",
          "age": 30,
          "hobbies": ["閱讀", "編程"],
          "address": {"city": "北京", "zipcode": "100000"}
      }
      
      # 將數(shù)據(jù)寫入JSON文件
      with open("data.json", "w", encoding="utf-8") as f:
          json.dump(data, f, ensure_ascii=False, indent=2)
      • ensure_ascii=False確保中文等非 ASCII 字符正確寫入文件。
      • indent=2使用 2 個(gè)空格縮進(jìn),讓 JSON 文件更易讀。

      若需將 JSON 數(shù)據(jù)打印到控制臺(tái)或日志中,可結(jié)合sys.stdout使用:

      import json
      import sys
      
      data = {"code": 200, "message": "操作成功", "data": [1, 2, 3]}
      json.dump(data, sys.stdout, ensure_ascii=False, indent=2)
      
      # 輸出結(jié)果:
      '''{
        "code": 200,
        "message": "操作成功",
        "data": [
          1,
          2,
          3
        ]
      }'''

      3.2.json.dumps():用于將 Python 對(duì)象(如字典、列表)轉(zhuǎn)換為 JSON 格式的字符串。這一過(guò)程也被稱為序列化(Serialization)。與json.dump()(寫入文件)不同,json.dumps()返回字符串,適用于網(wǎng)絡(luò)傳輸、打印輸出或內(nèi)存處理。

      json.dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True,
                 allow_nan=True, cls=None, indent=None, separators=None,
                 default=None, sort_keys=False, **kw)
      import json
      
      data = {
          "name": "張三",
          "age": 30,
          "hobbies": ["閱讀", "編程"],
          "is_student": False,
          "address": {"city": "北京", "zipcode": "100000"}
      }
      
      # 將Python對(duì)象轉(zhuǎn)換為JSON字符串
      json_str = json.dumps(data, ensure_ascii=False, indent=2)
      print(json_str)

      輸出結(jié)果

      {
        "name": "張三",
        "age": 30,
        "hobbies": ["閱讀", "編程"],
        "is_student": false,
        "address": {
          "city": "北京",
          "zipcode": "100000"
        }
      }

       網(wǎng)絡(luò)數(shù)據(jù)傳輸

      API 接口或網(wǎng)絡(luò)通信中,常將數(shù)據(jù)序列化為 JSON 字符串后發(fā)送:

      import requests
      import json
      
      data = {"user_id": 123, "action": "login"}
      json_payload = json.dumps(data)
      
      try:
          response = requests.post(
              "https://api.example.com/user",  # 替換為實(shí)際API地址
              data=json_payload,
              headers={"Content-Type": "application/json"}
          )
          response.raise_for_status()  # 檢查請(qǐng)求是否成功(狀態(tài)碼200)
      except requests.exceptions.ConnectionError as e:
          print(f"網(wǎng)絡(luò)連接錯(cuò)誤: {e}")
          print("請(qǐng)檢查域名是否正確、網(wǎng)絡(luò)是否正常連接。")
      except requests.exceptions.Timeout:
          print("請(qǐng)求超時(shí),請(qǐng)稍后重試。")
      except requests.exceptions.HTTPError as e:
          print(f"HTTP錯(cuò)誤: {e}")
      except requests.exceptions.RequestException as e:
          print(f"請(qǐng)求發(fā)生異常: {e}")
      else:
          print("請(qǐng)求成功!")
          print(response.json())  # 處理響應(yīng)數(shù)據(jù)
      函數(shù)名 功能描述
      json.dumps() 將 Python 對(duì)象序列化為字符串(返回值為字符串,適用于網(wǎng)絡(luò)傳輸)。
      json.dump() 將 Python 對(duì)象序列化并寫入文件(需傳入文件對(duì)象,如open('data.json', 'w'))。
      json.loads() 將 JSON 字符串反序列化為 Python 對(duì)象(解析字符串)。
      json.load() 從文件中讀取 JSON 數(shù)據(jù)并反序列化為 Python 對(duì)象

      4.re正則表達(dá)式數(shù)據(jù)解析(Regular Expression,簡(jiǎn)稱 Regex 或 RE)是一種強(qiáng)大的文本模式匹配工具,用于在字符串中查找、提取或替換符合特定模式的文本片段。正則表達(dá)式數(shù)據(jù)解析就是利用這種模式匹配能力,從復(fù)雜的文本數(shù)據(jù)中提取出結(jié)構(gòu)化的信息。

      正則表達(dá)式在數(shù)據(jù)解析中廣泛應(yīng)用于以下場(chǎng)景:
      • 文本提取:從網(wǎng)頁(yè)、日志文件、配置文件等非結(jié)構(gòu)化文本中提取特定信息
      • 數(shù)據(jù)驗(yàn)證:檢查輸入數(shù)據(jù)是否符合特定格式(如郵箱、URL、電話號(hào)碼)
      •  
      • 文本替換:根據(jù)特定模式批量替換文本內(nèi)容
      • 字符串分割:根據(jù)特定分隔符將字符串分割成多個(gè)部分
      • 日志分析:從系統(tǒng)日志中提取關(guān)鍵信息(如時(shí)間戳、錯(cuò)誤代碼)

      導(dǎo)入正則表達(dá)式庫(kù)re

      import re

      正則表達(dá)式測(cè)試網(wǎng)站:https://tool.oschina.net/regex

      • 普通字符:匹配自身,如a匹配字符 "a"
      • 元字符:具有特殊含義的字符,如.匹配任意字符
      • 字符類:[]表示,匹配方括號(hào)內(nèi)的任意一個(gè)字符,如[abc]匹配 "a"、"b" 或 "c"
      • 量詞:控制匹配次數(shù),如*表示 0 次或次,+表示 1 次或多次,?表示 0 次或 1
      • 邊界符:^表示字符串開始,$表示字符串結(jié)束
      • 分組:()表示,可以捕獲匹配的內(nèi)容,如(abc)匹配并捕獲 "abc"

      ①.基本元字符 

      元字符 描述
      . 匹配除換行符外的任意單個(gè)字符
      ^ 匹配字符串的開始位置
      $  匹配字符串的結(jié)束位置
      * 匹配前面的子表達(dá)式零次或多次
      + 匹配前面的子表達(dá)式一次或多次
      ? 匹配前面的子表達(dá)式零次或一次
      {n} 匹配前面的子表達(dá)式恰好 n 次
      {n,} 匹配前面的子表達(dá)式至少 n 次
      {n,m} 匹配前面的子表達(dá)式至少 n 次,最多 m 次

      ②.字符類元字符

      [] - 定義字符類,匹配方括號(hào)內(nèi)的任意一個(gè)字符

      • 例如:[abc] 匹配 'a'、'b' 'c'
      • 可以使用連字符表示范圍:[a-z] 匹配任意小寫字母
      • 開頭使用 ^ 表示取反:[^0-9] 匹配任意非數(shù)字字符

      ③.特殊字符類

      特殊字符 描述
      \d 匹配任意數(shù)字,等價(jià)于 [0-9]
      \D  匹配任意非數(shù)字,等價(jià)于 [^0-9]
      \w 匹配任意字母、數(shù)字或下劃線,等價(jià)于 [a-zA-Z0-9_]
      \W 匹配任意非字母、數(shù)字或下劃線,等價(jià)于 [^a-zA-Z0-9_]
      \s 匹配任意空白字符,包括空格、制表符、換頁(yè)符等
      \S 匹配任意非空白字符

      ④.分組和引用

      • () - 分組,將多個(gè)字符視為一個(gè)單元

      例如:(ab)+ 匹配一個(gè)或多個(gè)連續(xù)的 "ab"

      可以捕獲匹配的內(nèi)容,用于后續(xù)引用

      • \1\2, ... - 反向引用,引用前面捕獲的分組

      例如:(\w+) \1 匹配重復(fù)的單詞,如 "hello hello"

      ⑤.或操作符

      | - 邏輯或,匹配兩個(gè)或多個(gè)模式中的任意一個(gè)

      例如:cat|dog 匹配 "cat" 或 "dog"

      ⑥.轉(zhuǎn)義字符

      \ - 轉(zhuǎn)義字符,用于取消元字符的特殊含義

      例如:\. 匹配字面意義的點(diǎn)號(hào),也用于表示特殊字符類,如 \d\s 等

      ⑦.斷言(零寬度斷言)

      ?(?=...) - 正向肯定預(yù)查,匹配后面緊跟指定模式的位置

      例如:\w+(?=\d) 匹配后面跟數(shù)字的單詞

      ?(?!...) - 正向否定預(yù)查,匹配后面不緊跟指定模式的位置

      例如:\w+(?!\d) 匹配后面不跟數(shù)字的單詞

      ?(?<=...) - 反向肯定預(yù)查,匹配前面是指定模式的位置

      例如:(?<=\$)\d+ 匹配前面是美元符號(hào)的數(shù)字

      ?(?<!...) - 反向否定預(yù)查,匹配前面不是指定模式的位置

      例如:(?<!\$)\d+ 匹配前面不是美元符號(hào)的數(shù)字

      ⑧.其他元字符

      ?\b - 匹配單詞邊界,如 \bcat\b 只匹配獨(dú)立的 "cat" 單詞

      ?\B - 匹配非單詞邊界

      ?(?:...) - 非捕獲組,分組但不捕獲匹配的內(nèi)容

      ⑨.貪婪匹配和惰性匹配

      貪婪匹配:.* 意思是盡可能的去匹配結(jié)果

      惰性匹配:.*? 意思是盡可能的去匹配結(jié)果

      ⑩.常用的正則表達(dá)式格式

      手機(jī)號(hào)校驗(yàn)
      中國(guó)大陸手機(jī)號(hào)一般是 11 位數(shù)字,以 1 開頭,第二位可能是 3、4、5、6、7、8、9 等
      正則表達(dá)式:/^1[3456789]\d{9}$/
      解釋:
      ^ 表示匹配字符串的開始。
      1 表示手機(jī)號(hào)以 1 開頭。
      [3456789] 表示第二位是 3 到 9 中的任意一個(gè)數(shù)字。
      \d{9} 表示后面跟著 9 位數(shù)字。
      $ 表示匹配字符串的結(jié)束。
      郵箱校驗(yàn)
      正則表達(dá)式:/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
      解釋:
      ^ 匹配字符串開始。
      [a-zA-Z0-9._%+-]+ 表示用戶名部分,可以包含字母、數(shù)字、點(diǎn)、下劃線、百分號(hào)、加號(hào)和減號(hào),且至少有一個(gè)字符。
      @ 匹配 @ 符號(hào)。
      [a-zA-Z0-9.-]+ 表示域名部分,包含字母、數(shù)字、點(diǎn)和減號(hào)。
      \. 匹配實(shí)際的點(diǎn)號(hào)(因?yàn)辄c(diǎn)號(hào)在正則中有特殊含義,所以需要轉(zhuǎn)義)。
      [a-zA-Z]{2,} 表示頂級(jí)域名,至少有兩個(gè)字母。
      $ 匹配字符串結(jié)束。
      身份證號(hào)碼校驗(yàn)(18 位)
      正則表達(dá)式:/^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[0-9Xx]$/
      解釋:
      ^ 匹配字符串開始。
      [1-9]\d{5} 表示前 6 位地址碼,第一位不能是 0。
      (18|19|20)\d{2} 表示年份,限定在 1800 到 2099 之間。
      (0[1-9]|1[0-2]) 表示月份,01 到 12。
      (0[1-9]|[12]\d|3[01]) 表示日期,根據(jù)月份合理取值。
      \d{3} 表示順序碼。
      [0-9Xx] 表示校驗(yàn)碼,X 可以是大寫或小寫。
      $ 匹配字符串結(jié)束。
      密碼強(qiáng)度校驗(yàn)(至少包含字母和數(shù)字,長(zhǎng)度 8 到 20 位)
      正則表達(dá)式:/^(?=.*[a-zA-Z])(?=.*\d)[a-zA-Z\d]{8,20}$/大小寫皆可  或  /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/至少包含一個(gè)大寫字母。
      解釋:
      ^ 匹配字符串開始。
      (?=.*[a-zA-Z]) 是一個(gè)正向預(yù)查,表示字符串中至少有一個(gè)字母。
      (?=.*\d) 是一個(gè)正向預(yù)查,表示字符串中至少有一個(gè)數(shù)字。
      [a-zA-Z\d]{8,20} 表示由字母和數(shù)字組成,長(zhǎng)度在 8 到 20 位之間。
      $ 匹配字符串結(jié)束。
      URL校驗(yàn)
      正則表達(dá)式:/^(https?|ftp):\/\/([a-zA-Z0-9.-]+(\:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2})(:\d+)?(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
      解釋:
      ^ 匹配字符串開始。
      (https?|ftp) 匹配協(xié)議,可以是 http、https 或 ftp。
      :\/\/ 匹配 :// 分隔符。
      后面復(fù)雜的部分是對(duì)域名、IP 地址、端口、路徑等的匹配和限定。
      $ 匹配字符串結(jié)束。
      整數(shù)校驗(yàn)
      正則表達(dá)式:/^-?\d+$/
      解釋:
      ^ 匹配字符串開始。
      -? 表示可以有一個(gè)可選的負(fù)號(hào)。
      \d+ 表示一個(gè)或多個(gè)數(shù)字。
      $ 匹配字符串結(jié)束。
      正整數(shù)校驗(yàn)
      正則表達(dá)式:/^[1-9]\d*$/
      解釋:
      ^ 匹配字符串開始。
      [1-9] 表示第一位不能是 0,必須是 1 到 9 中的一個(gè)數(shù)字。
      \d* 表示后面可以跟零個(gè)或多個(gè)數(shù)字。
      $ 匹配字符串結(jié)束。
      浮點(diǎn)數(shù)校驗(yàn)
      正則表達(dá)式:/^-?\d+(\.\d+)?$/
      解釋:
      ^ 匹配字符串開始。
      -? 表示可以有一個(gè)可選的負(fù)號(hào)。
      \d+ 表示整數(shù)部分,至少一個(gè)數(shù)字。
      (\.\d+)? 表示小數(shù)部分是可選的,\. 匹配點(diǎn)號(hào),\d+ 表示至少一個(gè)數(shù)字。
      $ 匹配字符串結(jié)束。
      日期校驗(yàn)(YYYY-MM-DD 格式)
      正則表達(dá)式:/^((((1[6-9]|[2-9]\d)\d{2})(0[13578]|1[02])(0[1-9]|[12]\d|3[01]))|(((1[6-9]|[2-9]\d)\d{2})(0[13456789]|1[012])(0[1-9]|[12]\d|30))|(((1[6-9]|[2-9]\d)\d{2})02(0[1-9]|1\d|2[0-8]))|((((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26]))|((16|[2468][048]|[3579][26])00))0229))$/
      解釋:
      ^ 表示匹配字符串的開始。
      整體是多個(gè)分組的或關(guān)系(|)。
      ((((1[6-9]|[2-9]\d)\d{2})(0[13578]|1[02])(0[1-9]|[12]\d|3[01])) 匹配大月(1、3、5、7、8、10、12 月)有 31 天的日期,年份部分 (1[6-9]|[2-9]\d)\d{2} 表示 1600 年到 9999 年。
      (((1[6-9]|[2-9]\d)\d{2})(0[13456789]|1[012])(0[1-9]|[12]\d|30)) 匹配小月(除 2 月外有 30 天的月份)的日期。
      (((1[6-9]|[2-9]\d)\d{2})02(0[1-9]|1\d|2[0-8])) 匹配平年 2 月(28 天)的日期。
      ((((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26]))|((16|[2468][048]|[3579][26])00))0229)) 匹配閏年 2 月(29 天)的日期,閏年的判斷條件是能被 4 整除但不能被 100 整除,或者能被 400 整除。
      $ 表示匹配字符串的結(jié)束。
      車牌號(hào)校驗(yàn)(以中國(guó)大陸為例,普通民用汽車號(hào)牌)
      正則表達(dá)式:/^[京津滬渝冀豫云遼黑湘皖魯新蘇浙贛鄂桂甘晉蒙陜吉閩貴粵青藏川寧瓊使領(lǐng)A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9掛學(xué)警港澳]{1}$/
      解釋:
      ^ 匹配字符串開始。
      [京津滬渝冀豫云遼黑湘皖魯新蘇浙贛鄂桂甘晉蒙陜吉閩貴粵青藏川寧瓊使領(lǐng)A-Z]{1} 表示省份簡(jiǎn)稱或特殊標(biāo)識(shí)(如使、領(lǐng)),是一個(gè)字符。
      [A-Z]{1} 表示地區(qū)代碼,為一個(gè)大寫字母。
      [A-Z0-9]{4} 表示 4 位字母或數(shù)字。
      [A-Z0-9掛學(xué)警港澳]{1} 表示最后一位可能是字母、數(shù)字,或者特殊標(biāo)識(shí)(掛、學(xué)、警、港、澳)。
      $ 匹配字符串結(jié)束。
      郵政編碼校驗(yàn)(中國(guó)大陸)
      正則表達(dá)式:/^[1-9]\d{5}$/
      解釋:
      ^ 匹配字符串開始。
      [1-9] 表示第一位不能為 0,是 1 到 9 中的一個(gè)數(shù)字。
      \d{5} 表示后面跟著 5 位數(shù)字。
      $ 匹配字符串結(jié)束。
      中文姓名校驗(yàn)(一般情況,假設(shè)姓名為 2 到 4 個(gè)漢字)
      正則表達(dá)式:/^[\u4e00-\u9fa5]{2,4}$/
      解釋:
      ^ 匹配字符串開始。
      [\u4e00-\u9fa5] 表示匹配一個(gè)漢字,\u4e00 到 \u9fa5 是 Unicode 中漢字的編碼范圍。
      {2,4} 表示匹配 2 到 4 個(gè)這樣的漢字。
      $ 匹配字符串結(jié)束。
      英文單詞校驗(yàn)(由字母組成,可包含連字符,長(zhǎng)度不限)
      正則表達(dá)式:/^[a-zA-Z-]+$/
      解釋:
      ^ 匹配字符串開始。
      [a-zA-Z-] 表示可以是大寫或小寫字母,也可以是連字符。
      + 表示一個(gè)或多個(gè)這樣的字符。
      $ 匹配字符串結(jié)束。
      IPv4 地址校驗(yàn)
      正則表達(dá)式:/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
      解釋:
      ^ 匹配字符串開始。
      (25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?) 表示每個(gè)部分(0 到 255 的數(shù)字)的匹配規(guī)則,分別處理了不同范圍的數(shù)字情況。
      \. 匹配實(shí)際的點(diǎn)號(hào)(轉(zhuǎn)義)。
      重復(fù)四次上述部分來(lái)匹配 IPv4 地址的四個(gè)字節(jié)。
      $ 匹配字符串結(jié)束。
      銀行卡號(hào)校驗(yàn)(一般 16 到 19 位數(shù)字)
      正則表達(dá)式:/^\d{16,19}$/
      解釋:
      ^ 匹配字符串開始。
      \d{16,19} 表示由 16 到 19 位數(shù)字組成。
      $ 匹配字符串結(jié)束。

      4.1.re.findall(“正則表達(dá)式”,"原字符串","可選參數(shù)") Python 中 re 模塊提供的一個(gè)重要函數(shù),用于在字符串中查找所有匹配正則表達(dá)式的非重疊子串,并返回一個(gè)包含所有匹配結(jié)果的列表。如果沒(méi)有找到匹配的內(nèi)容,則返回空列表。

      re.findall(pattern, string, flags=0)
      • pattern:正則表達(dá)式模式字符串
      • string:需要被搜索的原始字符串
      • flags:可選參數(shù),用于指定匹配模式(如忽略大小寫、多行匹配等)

      re.findall()的返回結(jié)果取決于正則表達(dá)式中是否包含捕獲組:

      • 無(wú)捕獲組:直接返回所有匹配的子字符串列表
      • 有一個(gè)捕獲組:返回每個(gè)匹配中捕獲組的內(nèi)容列表
      • 有多個(gè)捕獲組:返回元組列表,每個(gè)元組包含一個(gè)匹配中所有捕獲組的內(nèi)容
      import re
      
      # 示例1:無(wú)捕獲組,匹配所有數(shù)字
      text1 = "hello 123 world 456"
      result1 = re.findall(r'\d+', text1)
      print(f"示例1結(jié)果: {result1}")  # 輸出: ['123', '456']
      
      # 示例2:有一個(gè)捕獲組,提取所有括號(hào)內(nèi)的內(nèi)容
      text2 = "apple (red), banana (yellow), cherry (red)"
      result2 = re.findall(r'\((.*?)\)', text2)
      print(f"示例2結(jié)果: {result2}")  # 輸出: ['red', 'yellow', 'red']
      
      # 示例3:有多個(gè)捕獲組,提取所有水果和顏色
      text3 = "apple=red, banana=yellow, cherry=red"
      result3 = re.findall(r'(\w+)=(\w+)', text3)
      print(f"示例3結(jié)果: {result3}")  # 輸出: [('apple', 'red'), ('banana', 'yellow'), ('cherry', 'red')]
      
      # 示例4:使用標(biāo)志參數(shù)忽略大小寫
      text4 = "Hello World, HELLO PYTHON"
      result4 = re.findall(r'hello', text4, re.IGNORECASE)
      print(f"示例4結(jié)果: {result4}")  # 輸出: ['Hello', 'HELLO']
      
      # 示例5:多行匹配模式
      text5 = "Line 1\nLine 2\nLine 3"
      result5 = re.findall(r'^Line \d', text5, re.MULTILINE)
      print(f"示例5結(jié)果: {result5}")  # 輸出: ['Line 1', 'Line 2', 'Line 3']    

      注意事項(xiàng)

      貪婪匹配與非貪婪匹配:

      正則表達(dá)式中的 * 和 + 是貪婪的,會(huì)盡可能多地匹配字符

      在量詞后加 ? 可以使其變?yōu)榉秦澙纺J剑M可能少地匹配字符

      邊界處理

      使用 ^ 和 $ 匹配字符串的開始和結(jié)束

      使用 \b 匹配單詞邊界,避免部分匹配

      轉(zhuǎn)義字符

      正則表達(dá)式中的特殊字符(如 .*+ 等)需要使用 \ 進(jìn)行轉(zhuǎn)義

      可以使用原始字符串(在字符串前加 r)避免 Python 字符串轉(zhuǎn)義的干擾

      捕獲組的使用

      不需要提取內(nèi)容時(shí),可以使用非捕獲組 (?:...) 提高效率

      多個(gè)捕獲組的結(jié)果按元組形式返回,注意順序和數(shù)量

      常見(jiàn)應(yīng)用場(chǎng)景

      • 提取數(shù)據(jù):從日志、HTML、JSON 等文本中提取關(guān)鍵信息
      • 數(shù)據(jù)驗(yàn)證:檢查輸入是否符合特定格式(如郵箱、手機(jī)號(hào))
      • 文本分割:根據(jù)特定模式分割字符串
      • 替換操作:配合 re.sub() 進(jìn)行復(fù)雜的文本替換

      4.2.re.finditer("正則表達(dá)式","原字符串","可選參數(shù)"):主要作用是在字符串中查找所有非重疊的匹配項(xiàng),并返回一個(gè)包含匹配對(duì)象的迭代器。

      re.finditer(pattern, string, flags=0)
      # 或(使用預(yù)編譯的正則對(duì)象)
      pattern_obj.finditer(string)
      • 返回值:一個(gè)迭代器,每個(gè)元素是 Match 對(duì)象(包含單次匹配的詳細(xì)信息)。

      核心特點(diǎn)

      1. 返回迭代器:相比 findall() 直接返回匹配結(jié)果列表,finditer() 返回的迭代器更節(jié)省內(nèi)存(尤其處理大字符串時(shí))。
      2. 保留匹配細(xì)節(jié):每個(gè) Match 對(duì)象包含匹配的文本、位置、分組等信息(如命名分組、索引分組)。
      3. 非重疊匹配:只返回不重疊的匹配項(xiàng)(例如用 'aa' 匹配 'aaaa',會(huì)得到 ['aa', 'aa'] 而非 ['aa', 'aa', 'aa'])。

      常用操作(結(jié)合 Match 對(duì)象)

      通過(guò)迭代器獲取的 Match 對(duì)象有以下常用方法 / 屬性:
      • group(n)返回第 n 個(gè)分組的匹配結(jié)果(n=0 或省略時(shí)返回整個(gè)匹配文本;命名分組可用 group('name'))。
      • groups()返回所有分組的匹配結(jié)果組成的元組。
      • span()返回匹配文本在原始字符串中的起始和結(jié)束索引(元組 (start, end))。
      import re
      
      # 假設(shè)這是從網(wǎng)頁(yè)獲取的 HTML 片段(簡(jiǎn)化版)
      html = '''
      <div class="item">
          <span class="title">肖申克的救贖</span>
      </div>
      <div class="item">
          <span class="title">霸王別姬</span>
      </div>
      '''
      
      # 預(yù)編譯正則(匹配電影名稱)
      pattern = re.compile(r'<span class="title">(?P<name>.*?)</span>', re.S)
      
      # 使用 finditer() 查找所有匹配
      matches = pattern.finditer(html)
      
      # 遍歷迭代器,提取每個(gè)匹配的信息
      for match in matches:
          # 獲取整個(gè)匹配的文本(包含標(biāo)簽)
          print("完整匹配:", match.group(0))  # <span class="title">肖申克的救贖</span>
          
          # 獲取命名分組 'name' 的內(nèi)容(電影名稱)
          print("電影名稱:", match.group('name'))  # 肖申克的救贖
          
          # 獲取匹配的位置(在原始字符串中的索引)
          print("位置:", match.span())  # (例如 (19, 45),具體值取決于字符串)
          print("---")

      4.3.re.sub("正則表達(dá)式","替換的字符串","原字符串","可選參數(shù)"):用于在字符串中替換所有匹配正則表達(dá)式的子串。這是處理文本數(shù)據(jù)時(shí)非常常用的功能,比如清洗數(shù)據(jù)、格式化文本等。

      re.sub(pattern, repl, string, count=0, flags=0)
      • pattern正則表達(dá)式模式字符串,用于匹配需要替換的子串
      • repl替換字符串或可調(diào)用對(duì)象,用于替換匹配到的內(nèi)容
      • string需要被處理的原始字符串
      • count可選參數(shù),指定最多替換次數(shù)(默認(rèn)為 0,表示全部替換)
      • flags可選參數(shù),用于指定匹配模式(如忽略大小寫、多行匹配等)

      替換字符串的特殊語(yǔ)法

      當(dāng) repl 是字符串時(shí),可以使用以下特殊語(yǔ)法:

      • \g<group>:引用指定編號(hào)或名稱的捕獲組
      • \1\2, ...:引用第 1、2 等捕獲組
      • \g<0>:引用整個(gè)匹配的子串
      import re
      
      # 示例1:簡(jiǎn)單替換,將所有數(shù)字替換為X
      text1 = "hello 123 world 456"
      result1 = re.sub(r'\d', 'X', text1)
      print(f"示例1結(jié)果: {result1}")  # 輸出: hello XXX world XXX
      
      # 示例2:使用捕獲組,交換姓名順序
      text2 = "Zhang San, Li Si, Wang Wu"
      result2 = re.sub(r'(\w+) (\w+)', r'\2 \1', text2)
      print(f"示例2結(jié)果: {result2}")  # 輸出: San Zhang, Si Li, Wu Wang
      
      # 示例3:使用命名捕獲組,格式化日期
      text3 = "2023-10-01"
      result3 = re.sub(r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})', 
                       r'\g<month>/\g<day>/\g<year>', text3)
      print(f"示例3結(jié)果: {result3}")  # 輸出: 10/01/2023
      
      # 示例4:使用函數(shù)進(jìn)行動(dòng)態(tài)替換,將數(shù)字乘以2
      def double_number(match):
          return str(int(match.group(0)) * 2)
      
      text4 = "A1B2C3"
      result4 = re.sub(r'\d', double_number, text4)
      print(f"示例4結(jié)果: {result4}")  # 輸出: A2B4C6
      
      # 示例5:限制替換次數(shù)
      text5 = "apple apple apple"
      result5 = re.sub(r'apple', 'orange', text5, count=2)
      print(f"示例5結(jié)果: {result5}")  # 輸出: orange orange apple
      
      # 示例6:忽略大小寫替換
      text6 = "Hello World, hello Python"
      result6 = re.sub(r'hello', 'hi', text6, flags=re.IGNORECASE)
      print(f"示例6結(jié)果: {result6}")  # 輸出: hi World, hi Python    

      使用可調(diào)用對(duì)象作為替換參數(shù)

      當(dāng) repl 是一個(gè)函數(shù)時(shí),每次匹配成功后,該函數(shù)會(huì)被調(diào)用,傳入匹配對(duì)象(match)作為參數(shù),并返回替換字符串。這在需要根據(jù)匹配內(nèi)容進(jìn)行動(dòng)態(tài)替換時(shí)非常有用。

       

      例如,將字符串中的所有數(shù)字替換為其平方值:
      def square_number(match):
          num = int(match.group(0))
          return str(num ** 2)
      
      text = "a1b2c3"
      result = re.sub(r'\d', square_number, text)
      print(result)  # 輸出: a1b4c9

      常見(jiàn)應(yīng)用場(chǎng)景

      • 數(shù)據(jù)清洗:移除或替換特殊字符、多余空格等
      • 文本格式化:將日期、電話號(hào)碼等轉(zhuǎn)換為統(tǒng)一格式
      • 敏感信息處理:替換或掩碼化敏感數(shù)據(jù)(如身份證號(hào)、信用卡號(hào))
      • 語(yǔ)法轉(zhuǎn)換:在不同編程語(yǔ)言或格式之間轉(zhuǎn)換語(yǔ)法
      • 模板替換:根據(jù)規(guī)則動(dòng)態(tài)生成文本內(nèi)容

      注意事項(xiàng)

      • 正則表達(dá)式轉(zhuǎn)義

      正則表達(dá)式中的特殊字符需要使用 \ 進(jìn)行轉(zhuǎn)義

      可以使用原始字符串(如 r'\d+')避免 Python 字符串轉(zhuǎn)義的干擾

      • 捕獲組的使用

      使用 () 定義捕獲組,可以在替換字符串中引用

      使用非捕獲組 (?:...) 避免不必要的捕獲,提高效率

      • 替換字符串中的反斜杠

      替換字符串中的反斜杠需要轉(zhuǎn)義(如 \\ 表示一個(gè)反斜杠)

      • 可以使用原始字符串簡(jiǎn)化處理(如 r'\\section'
      通過(guò)合理使用 re.sub(),可以高效地完成各種復(fù)雜的文本替換任務(wù)。

      4.4.re.finditer("正則表達(dá)式","原字符串","可選參數(shù)"):函數(shù)來(lái)查找字符串中的所有數(shù)字。這個(gè)函數(shù)與 re.findall() 類似,但返回的是一個(gè)迭代器(iterator),每次迭代返回一個(gè)匹配對(duì)象(match object)。

      re.finditer(pattern, string, flags=0)
      • group(0):返回整個(gè)匹配的字符串
      • start():返回匹配開始的位置
      • end():返回匹配結(jié)束的位置
      • span():返回一個(gè)元組 (start, end)
      result = re.finditer(r"\d+", "我今年42歲,我有2000000元")
      for item in result:
          print(item.group(0))
      #輸出結(jié)果:42    2000000
      import re
      
      # 使用 re.finditer() 查找所有數(shù)字
      result = re.finditer(r"\d+", "我今年42歲,我有2000000元")
      
      # 遍歷迭代器并打印匹配結(jié)果
      for match in result:
          print(f"匹配到的數(shù)字: {match.group(0)}")
          print(f"位置: {match.start()} - {match.end()}")
          print(f"原始字符串中的片段: {match.string[match.start():match.end()]}")
          print("-" * 20)
      
      """輸出結(jié)果:
      匹配到的數(shù)字: 42
      位置: 3 - 5
      原始字符串中的片段: 42
      --------------------
      匹配到的數(shù)字: 2000000
      位置: 8 - 15
      原始字符串中的片段: 2000000
      --------------------"""

      與findall()的對(duì)比

      • re.findall():返回所有匹配的字符串列表
      • re.finditer():返回一個(gè)迭代器,每次迭代返回一個(gè)匹配對(duì)象
      當(dāng)處理大量數(shù)據(jù)時(shí),re.finditer() 更節(jié)省內(nèi)存,因?yàn)樗恍枰淮涡源鎯?chǔ)所有匹配結(jié)果。
      4.5.re.search("正則表達(dá)式","原字符串","可選參數(shù)"):用于在字符串中搜索第一個(gè)匹配正則表達(dá)式的位置。與 re.findall() 和 re.finditer() 不同,re.search() 只返回第一個(gè)匹配結(jié)果,如果沒(méi)有找到則返回 None
      re.search(pattern, string, flags=0)
      • pattern:正則表達(dá)式模式字符串
      • string:需要被搜索的原始字符串
      • flags:可選參數(shù),用于指定匹配模式(如忽略大小寫、多行匹配等)

      返回值

      如果找到匹配項(xiàng),返回一個(gè) 匹配對(duì)象(match object),否則返回 None。匹配對(duì)象包含以下常用方法和屬性:
      • group(0):返回整個(gè)匹配的字符串
      • group(1), group(2), ...:返回第 1、2 等捕獲組的內(nèi)容
      • start():返回匹配開始的位置
      • end():返回匹配結(jié)束的位置
      • span():返回一個(gè)元組 (start, end)
      import re
      
      # 示例1:查找第一個(gè)數(shù)字
      text1 = "hello 123 world 456"
      match1 = re.search(r'\d+', text1)
      if match1:
          print(f"找到數(shù)字: {match1.group(0)}")  # 輸出: 123
          print(f"位置: {match1.start()} - {match1.end()}")  # 輸出: 6 - 9
      else:
          print("未找到匹配項(xiàng)")
      
      # 示例2:使用捕獲組提取信息
      text2 = "我的郵箱是 example@domain.com,請(qǐng)查收"
      match2 = re.search(r'(\w+)@(\w+\.\w+)', text2)
      if match2:
          print(f"完整郵箱: {match2.group(0)}")  # 輸出: example@domain.com
          print(f"用戶名: {match2.group(1)}")  # 輸出: example
          print(f"域名: {match2.group(2)}")  # 輸出: domain.com
      
      # 示例3:忽略大小寫查找
      text3 = "Hello World"
      match3 = re.search(r'world', text3, re.IGNORECASE)
      if match3:
          print(f"找到匹配: {match3.group(0)}")  # 輸出: World
      
      # 示例4:多行模式下的搜索
      text4 = "第一行\(zhòng)n第二行\(zhòng)n第三行"
      match4 = re.search(r'^第(.*)行$', text4, re.MULTILINE)
      if match4:
          print(f"匹配行內(nèi)容: {match4.group(0)}")  # 輸出: 第一行
          print(f"捕獲內(nèi)容: {match4.group(1)}")  # 輸出: 一    

      常見(jiàn)應(yīng)用場(chǎng)景

      • 檢查字符串中是否存在特定模式:
      import re
      
      # 通過(guò)用戶輸入獲取密碼
      password = input("請(qǐng)輸入密碼:")
      
      if re.search(r'^[a-zA-Z0-9]+$', password):
          print("密碼格式有效")
      else:
          print("密碼格式無(wú)效,只能包含字母和數(shù)字")
      • 提取特定信息:
      import re
      
      # 定義要搜索的文本
      text = "這是一個(gè)測(cè)試,商品價(jià)格:99.99元"
      
      match = re.search(r'價(jià)格:(\d+\.\d+)元', text)
      if match:
          price = float(match.group(1))
          print(f"商品價(jià)格: {price} 元")
      else:
          print("未找到價(jià)格信息")
      #輸出結(jié)果:商品價(jià)格: 99.99 元
      
      #從用戶輸入獲取 text
      import re
      
      # 從用戶輸入獲取文本
      text = input("請(qǐng)輸入包含價(jià)格的文本(例如:商品價(jià)格:99.99元):")
      
      # 修改正則表達(dá)式,允許匹配整數(shù)或小數(shù)價(jià)格
      match = re.search(r'價(jià)格:(\d+(?:\.\d+)?)元', text)
      
      if match:
          try:
              price = float(match.group(1))
              print(f"成功提取價(jià)格: {price} 元")
          except ValueError:
              print("錯(cuò)誤:無(wú)法將提取的內(nèi)容轉(zhuǎn)換為價(jià)格")
      else:
          print("未找到符合格式的價(jià)格信息")
          print("提示:請(qǐng)確保輸入的文本包含如'價(jià)格:99.99元'或'價(jià)格:100元'的格式")
      
      import re
      
      # 從文件讀取文本
      try:
          with open('input.txt', 'r', encoding='utf-8') as file:
              text = file.read()
      except FileNotFoundError:
          print("文件未找到,請(qǐng)檢查文件路徑")
          exit()
      
      match = re.search(r'價(jià)格:(\d+\.\d+)元', text)
      if match:
          price = float(match.group(1))
          print(f"商品價(jià)格: {price} 元")
      else:
          print("未找到價(jià)格信息")
      • 驗(yàn)證輸入格式:
      import re
      
      # 通過(guò)用戶輸入獲取電話號(hào)碼
      phone_number = input("請(qǐng)輸入電話號(hào)碼:")
      
      if re.search(r'^\d{11}$', phone_number):
          print("手機(jī)號(hào)碼格式正確")
      else:
          print("手機(jī)號(hào)碼格式錯(cuò)誤,必須是11位數(shù)字"

      注意事項(xiàng)

      • 匹配對(duì)象的判斷:
        • 由于 re.search() 可能返回 None,在使用前應(yīng)先檢查是否為 None
        • 示例:match = re.search(pattern, string) → if match:
      • 捕獲組的編號(hào):
        • 捕獲組從 1 開始編號(hào),group(0) 表示整個(gè)匹配
        • 嵌套捕獲組的編號(hào)按照左括號(hào)出現(xiàn)的順序確定
      • 正則表達(dá)式的邊界:
        • 使用 ^ 和 $ 來(lái)限制匹配的范圍
        • 例如:re.search(r'^hello$', text) 要求整個(gè)字符串必須是 "hello"
      • 通過(guò)合理使用 re.search(),可以高效地完成各種文本搜索和提取任務(wù)。

      4.6.re.match("正則表達(dá)式","原字符串","可選參數(shù)"):主要用于在字符串的起始位置對(duì)正則表達(dá)式進(jìn)行匹配。要是匹配成功,它會(huì)返回一個(gè)匹配對(duì)象;要是匹配失敗,則返回None

      re.match(pattern, string, flags=0)

      參數(shù)說(shuō)明

      • pattern:此為必選參數(shù),代表的是要進(jìn)行匹配的正則表達(dá)式。
      • string:同樣是必選參數(shù),指的是需要被匹配的字符串。
      • flags:這是可選參數(shù),用于指定匹配模式,像忽略大小寫、多行匹配等。該參數(shù)的值可以是多個(gè)標(biāo)志的按位或運(yùn)算結(jié)果(例如re.I | re.M)。

      核心特性

      • 僅匹配開頭re.match只會(huì)從字符串的起始位置開始嘗試匹配。若起始位置不符合正則表達(dá)式,即便后續(xù)部分有符合的內(nèi)容,也會(huì)匹配失敗。
      • 返回匹配對(duì)象:一旦匹配成功,就會(huì)返回一個(gè)包含匹配信息的對(duì)象。借助這個(gè)對(duì)象,你可以獲取匹配的內(nèi)容、位置等信息。

      匹配對(duì)象的常用方法

      當(dāng)re.match返回匹配對(duì)象后,可以使用以下方法獲取匹配信息:
      • group([group1, ...])用于獲取一個(gè)或多個(gè)分組的匹配內(nèi)容。若不指定參數(shù),則返回整個(gè)匹配結(jié)果。
      • groups()返回一個(gè)包含所有分組匹配結(jié)果的元組。
      • start([group])返回指定分組匹配的起始位置。若未指定分組,則返回整個(gè)匹配的起始位置。
      • end([group])返回指定分組匹配的結(jié)束位置(不包含該位置的字符)。
      • span([group])返回一個(gè)元組,包含指定分組匹配的起始和結(jié)束位置。

      re.matchre.search的區(qū)別

      • re.match只在字符串的起始位置進(jìn)行匹配。
      • re.search會(huì)在整個(gè)字符串中進(jìn)行搜索匹配,只要找到第一個(gè)匹配項(xiàng)就會(huì)返回。
      import re
      
      string = "Hello, world!"
      match = re.match("world", string)  # 匹配失敗,返回None
      search = re.search("world", string)  # 匹配成功,返回匹配對(duì)象
      
      print(match)  # 輸出:None
      print(search.group())  # 輸出:world

      注意事項(xiàng)

      • 正則表達(dá)式的轉(zhuǎn)義:在正則表達(dá)式里,像.*+這類字符有特殊含義。如果要匹配它們的字面意思,需要使用反斜杠\進(jìn)行轉(zhuǎn)義。
      • 原始字符串:編寫正則表達(dá)式時(shí),建議使用原始字符串(即在字符串前加r),這樣可以避免 Python 本身的轉(zhuǎn)義問(wèn)題。例如,匹配反斜杠本身時(shí),使用r'\\''\\\\'更清晰。

      4.7.re.compile("正則表達(dá)式","可選參數(shù)"):用于將正則表達(dá)式模式編譯為一個(gè)正則表達(dá)式對(duì)象。編譯后的對(duì)象可以多次使用,叫做預(yù)加載,提高匹配效率,尤其在需要重復(fù)匹配相同模式的場(chǎng)景下性能更優(yōu)。

      re.compile(pattern, flags=0)
      • pattern要編譯的正則表達(dá)式模式。
      • flags可選參數(shù),用于指定正則表達(dá)式的匹配模式,如忽略大小寫、多行匹配等。
      import re
      
      # 編譯正則表達(dá)式
      pattern = re.compile(r'\d+')  # 匹配一個(gè)或多個(gè)數(shù)字
      
      # 使用編譯后的對(duì)象進(jìn)行匹配
      text = "Hello 123 World 456"
      
      # 查找所有匹配
      matches = pattern.findall(text)
      print(f"所有匹配: {matches}")  # 輸出: ['123', '456']
      
      # 使用 search 方法查找第一個(gè)匹配
      match = pattern.search(text)
      if match:
          print(f"第一個(gè)匹配: {match.group(0)}, 位置: {match.start()}")  # 輸出: 第一個(gè)匹配: 123, 位置: 6

      與直接使用模塊函數(shù)的比較

      直接使用 re 模塊的函數(shù)如 re.findall()re.search()時(shí),Python 會(huì)在內(nèi)部自動(dòng)編譯正則表達(dá)式。而使用 re.compile 可以顯式編譯正則表達(dá)式,避免重復(fù)編譯,提高性能。

      不使用 compile(自動(dòng)編譯)

      import re
      text = "Hello 123 World 456"
      matches = re.findall(r'\d+', text)  # 每次調(diào)用都編譯一次正則表達(dá)式
      print(matches)#輸出:['123','456']

      使用 compile(預(yù)編譯)

      import re
      pattern = re.compile(r'\d+')  # 編譯一次
      matches1 = pattern.findall("Hello 123")  # 直接使用已編譯的對(duì)象
      matches2 = pattern.findall("World 456")  # 再次使用,無(wú)需重新編譯
      print(matches1)  # 輸出: ['123']
      print(matches2)  # 輸出: ['456']

      編譯后的對(duì)象支持的方法

      編譯后的正則表達(dá)式對(duì)象支持與 re 模塊相同的方法,例如:
      • pattern.match(string[, pos[, endpos]])從字符串的起始位置開始匹配。
      • pattern.search(string[, pos[, endpos]])在字符串中搜索第一個(gè)匹配項(xiàng)。
      • pattern.findall(string[, pos[, endpos]])返回所有匹配的字符串列表。
      • pattern.finditer(string[, pos[, endpos]])返回匹配對(duì)象的迭代器。
      • pattern.sub(repl, string[, count])替換匹配的子串。

      性能優(yōu)化場(chǎng)景

      import re
      
      # 預(yù)編譯正則表達(dá)式
      email_pattern = re.compile(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b')
      
      # 待驗(yàn)證的郵箱列表
      emails = ["test@example.com", "invalid.email", "user.name+tag@domain.co.uk"]
      
      # 循環(huán)驗(yàn)證郵箱
      for email in emails:
          if email_pattern.match(email):
              print(f"{email} 是有效的郵箱地址")
          else:
              print(f"{email} 不是有效的郵箱地址")

      編譯標(biāo)志(Flags)

      re.compile 支持與 re 模塊函數(shù)相同的標(biāo)志參數(shù),例如:
      • re.IGNORECASE 或 re.I忽略大小寫。
      • re.MULTILINE 或 re.M多行匹配模式。
      • re.DOTALL 或 re.S使 . 匹配包括換行符在內(nèi)的所有字符。
      import re  # 添加模塊導(dǎo)入語(yǔ)句
      pattern = re.compile(r'hello', re.IGNORECASE)  # 忽略大小寫的匹配
      print(pattern.search("Hello World").group(0))  # 輸出: Hello

      總之,re.compile 是優(yōu)化正則表達(dá)式性能的重要工具,尤其適用于需要重復(fù)使用同一模式的場(chǎng)景。

      4.8.re.S: 匹配模式修飾符,也可以寫作 re.DOTALL

      它的作用是改變 .(點(diǎn)號(hào))的匹配行為:
        • 默認(rèn)情況下,. 可以匹配除換行符 \n 之外的任意字符
        • 當(dāng)使用 re.S 模式后,. 可以匹配包括換行符 \n 在內(nèi)的任意字符
      import re
      
      text = "hello\nworld"
      
      # 不使用 re.S,無(wú)法匹配換行符
      print(re.findall("hello.world", text))  # 輸出: []
      
      # 使用 re.S,點(diǎn)號(hào)可以匹配換行符
      print(re.findall("hello.world", text, re.S))  # 輸出: ['hello\nworld']

      這個(gè)修飾符在需要匹配多行文本時(shí)非常有用,比如處理包含換行的字符串或多行文本內(nèi)容。re.DOTALL 是更具描述性的別名,功能與 re.S 完全相同。

      re正則表達(dá)式代碼示例:

      obj = re.compile(r'<div class="item">.*?<span class="title">(?P<name>.*?)</span>', re.S)

      代碼解釋:

      這段代碼使用 Python re.compile() 函數(shù)編譯了一個(gè)正則表達(dá)式模式,用于從 HTML 文本中提取特定標(biāo)簽內(nèi)的內(nèi)容。以下是逐部分解釋:

      1. 核心函數(shù):re.compile()

      re.compile(pattern, flags) 是 Python 正則模塊 re 的核心函數(shù),作用是將正則表達(dá)式字符串預(yù)編譯為一個(gè)正則對(duì)象(這里賦值給 obj)。預(yù)編譯的好處是:如果需要多次使用該正則表達(dá)式(比如循環(huán)匹配多頁(yè)內(nèi)容),編譯后可以提高執(zhí)行效率。

      2. 正則表達(dá)式模式:r'<div class="item">.*?<span class="title">(?P<name>.*?)</span>'

      這是一個(gè)原始字符串(前綴 r 表示不解析轉(zhuǎn)義字符,避免正則中的 \ 被誤處理),用于精準(zhǔn)匹配 HTML 中特定結(jié)構(gòu)的內(nèi)容:
      • <div class="item">匹配 HTML 中 class 屬性為 item  <div> 標(biāo)簽(豆瓣 Top250 中每個(gè)電影條目都包裹在這樣的 <div> 里,是單個(gè)電影信息的外層容器)。
      • .*?非貪婪匹配(.* 匹配任意字符,? 表示盡可能少匹配),用于跳過(guò) <div> 和 <span> 之間的內(nèi)容。
      • <span class="title">:匹配 class 屬性為 title 的 <span> 標(biāo)簽(豆瓣電影名稱通常放在這個(gè)標(biāo)簽內(nèi)),是電影名稱的 “開始標(biāo)記”。
      • (?P<name>.*?):命名分組(核心部分):
      • (?P<name>...) 是 Python 正則的語(yǔ)法,給括號(hào)內(nèi)匹配的內(nèi)容起一個(gè)名字(這里叫 name),后續(xù)可以通過(guò) group('name') 直接提取該部分內(nèi)容,無(wú)需記索引位置。
      • *? 非貪婪匹配 <span class="title"> 和 </span> 之間的文本(即我們要提取的電影名稱)。
      • </span>匹配 <span> 標(biāo)簽的閉合標(biāo)簽,作為電影名稱的 “結(jié)束標(biāo)記”,確保只提取標(biāo)簽內(nèi)的文本。

      3. 標(biāo)志位:re.S

      re.S 是正則表達(dá)式的標(biāo)志位(也可寫作 re.DOTALL),作用是:讓 .(匹配任意字符)可以匹配換行符 \n
      在 HTML 中,標(biāo)簽可能跨多行(如:
      <div class="item">
          <div class="other-info">...</div>
          <span class="title">肖申克的救贖</span>
      </div>
      如果不加 re.S.*? 會(huì)在換行符處停止匹配,導(dǎo)致無(wú)法跨越換行找到 <span class="title">加了 re.S 后,.*? 可以匹配包括換行在內(nèi)的所有字符,確保整個(gè)結(jié)構(gòu)被正確匹配。

      總結(jié)

      這段代碼的作用是:
       
      預(yù)編譯一個(gè)正則表達(dá)式,專門用于從豆瓣 Top250 頁(yè)面的 HTML 中,匹配每個(gè)電影條目<div class="item">內(nèi)的電影名稱標(biāo)簽(<span class="title">,并將標(biāo)簽內(nèi)的電影名稱提取出來(lái),命名為 name 以便后續(xù)使用。
       
      搭配 finditer() 等方法使用時(shí),就能批量提取頁(yè)面中的所有電影名稱了(例如:for item in obj.finditer(html): print(item.group('name')))。
      import requests
      import re
      
      # 1. 獲取頁(yè)面
      url = 'https://movie.douban.com/top250'
      headers = {
          'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36'
      }
      response = requests.get(url=url, headers=headers)
      response.encoding = 'utf-8'  # 正確設(shè)置編碼的方式
      
      # 2. 正則表達(dá)式提取電影名稱   
      # 編譯正則表達(dá)式
      obj = re.compile(r'<div class="item">.*?<span class="title">(?P<name>.*?)</span>', re.S)
      # 查找所有匹配結(jié)果
      result = obj.finditer(response.text)
      
      # 遍歷結(jié)果并打印
      for item in result:  # 正確的循環(huán)語(yǔ)法:for ... in ...
          print(item.group('name'))

      5.CSV文件寫入(內(nèi)置模塊)

      5.1. 基礎(chǔ)寫入方法:使用csv.writer可以寫入列表數(shù)據(jù)到 CSV 文件:

      import csv
      
      # 數(shù)據(jù)
      data = [
          ["姓名", "年齡", "城市"],
          ["張三", 25, "北京"],
          ["李四", 30, "上海"],
          ["王五", 28, "廣州"]
      ]
      
      # 寫入CSV文件
      with open("people.csv", "w", newline="", encoding="utf-8") as file:
          writer = csv.writer(file)
          # 寫入多行
          writer.writerows(data)
          # 也可以單行寫入
          # writer.writerow(["趙六", 35, "深圳"])

      5.2. 字典方式寫入:如果數(shù)據(jù)以字典形式存在,可以使用csv.DictWriter

      import csv
      
      # 數(shù)據(jù)
      data = [
          {"姓名": "張三", "年齡": 25, "城市": "北京"},
          {"姓名": "李四", "年齡": 30, "城市": "上海"},
          {"姓名": "王五", "年齡": 28, "城市": "廣州"}
      ]
      
      # 字段名(表頭)
      fieldnames = ["姓名", "年齡", "城市"]
      
      with open("people_dict.csv", "w", newline="", encoding="utf-8") as file:
          writer = csv.DictWriter(file, fieldnames=fieldnames)
          # 寫入表頭
          writer.writeheader()
          # 寫入數(shù)據(jù)
          writer.writerows(data)
          # 單行寫入
          # writer.writerow({"姓名": "趙六", "年齡": 35, "城市": "深圳"})

      5.3. 自定義分隔符:默認(rèn)情況下,CSV 使用逗號(hào)作為分隔符,你可以通過(guò)delimiter參數(shù)自定義

      import csv
      
      with open("custom_sep.csv", "w", newline="", encoding="utf-8") as file:
          # 使用制表符作為分隔符(類似TSV文件)
          writer = csv.writer(file, delimiter="\t")
          writer.writerows([["a", "b", "c"], ["1", "2", "3"]])

      注意事項(xiàng):

      • 使用newline=""參數(shù)可以避免在 Windows 系統(tǒng)中出現(xiàn)多余的空行
      • 指定encoding="utf-8"可以確保中文正常顯示
      • 寫入完成后,文件會(huì)自動(dòng)關(guān)閉(因?yàn)槭褂昧?strong>with語(yǔ)句)
      這些方法可以滿足大多數(shù) CSV 文件寫入需求,根據(jù)你的數(shù)據(jù)格式選擇合適的方式即可。

      5.4.enumerate(迭代對(duì)象,[0]:):枚舉對(duì)象轉(zhuǎn)換:用于將一個(gè)可迭代對(duì)象(如列表、元組、字符串等)轉(zhuǎn)換為一個(gè)枚舉對(duì)象,在遍歷過(guò)程中同時(shí)返回「元素的索引」和「元素的值」

      enumerate(iterable, start=0)
      • iterable需要遍歷的可迭代對(duì)象(如列表、字符串等)
      • start可選參數(shù),指定索引的起始值,默認(rèn)從 0 開始

      作用和優(yōu)勢(shì):

      當(dāng)你需要遍歷一個(gè)序列,同時(shí)又需要知道每個(gè)元素在序列中的位置(索引)時(shí),enumerate() 可以簡(jiǎn)化代碼。

      例如,不使用 enumerate() 時(shí),可能需要這樣寫:

      fruits = ['apple', 'banana', 'cherry']
      index = 0
      for fruit in fruits:
          print(f"Index: {index}, Fruit: {fruit}")
          index += 1  # 手動(dòng)維護(hù)索引

      而使用 enumerate() 后,代碼更簡(jiǎn)潔:

      fruits = ['apple', 'banana', 'cherry']
      for index, fruit in enumerate(fruits):
          print(f"Index: {index}, Fruit: {fruit}")
      '''
      輸出結(jié)果:
      Index: 1, Fruit: apple
      Index: 2, Fruit: banana
      Index: 3, Fruit: cherry
      '''

      如果從第二個(gè)數(shù)據(jù)(banana)開始迭代,可以先對(duì)列表進(jìn)行切片處理,從索引 1 開始(因?yàn)?Python 列表索引從 0 開始,第二個(gè)元素的索引是 1),再傳入enumerate()函數(shù)中。

      fruits = ['apple', 'banana', 'cherry']
      
      # 從索引1開始切片,只處理'banana'和'cherry'
      for index, fruit in enumerate(fruits[1:]):
          # 注意:此時(shí)的index是相對(duì)于切片后列表的索引(從0開始)
          # 如果需要顯示原列表中的真實(shí)索引,需要加上偏移量1
          print(f"原索引: {index + 1}, Fruit: {fruit}")
      '''
      輸出結(jié)果:
      原索引: 1, Fruit: banana
      原索引: 2, Fruit: cherry
      '''

      簡(jiǎn)單說(shuō),enumerate() 的核心作用就是在遍歷過(guò)程中同時(shí)獲取元素及其位置信息,讓代碼更簡(jiǎn)潔高效。

       

      自動(dòng)爬蟲

      1.selemium:是一套用于Web應(yīng)用程序自動(dòng)化測(cè)試的工具集,同時(shí)也廣泛用于網(wǎng)絡(luò)數(shù)據(jù)爬取(合規(guī)場(chǎng)景下)、自動(dòng)化操作瀏覽器(如自動(dòng)填寫表單、模擬用戶交互等)。它的核心能力是直接控制瀏覽器(如 Chrome、Firefox),模擬真實(shí)用戶的操作行為(點(diǎn)擊、輸入、跳轉(zhuǎn)等),是 Web 自動(dòng)化領(lǐng)域最流行的工具之一。

      一、Selenium 核心組件

      Selenium 并非單一工具,而是由多個(gè)組件構(gòu)成,不同組件適用于不同場(chǎng)景:
      組件名稱核心作用適用場(chǎng)景
      Selenium WebDriver 核心組件,提供編程語(yǔ)言接口(如 Python、Java),直接控制瀏覽器執(zhí)行操作 主流自動(dòng)化場(chǎng)景(測(cè)試、爬蟲)
      Selenium IDE 瀏覽器插件(支持 Chrome/Firefox),可視化錄制 / 回放用戶操作,無(wú)需寫代碼 快速生成簡(jiǎn)單自動(dòng)化腳本
      Selenium Grid 分布式測(cè)試工具,支持在多臺(tái)機(jī)器、多個(gè)瀏覽器上同時(shí)執(zhí)行自動(dòng)化腳本 大規(guī)模測(cè)試任務(wù)(提高效率)

      二、Selenium 核心原理

      Selenium 實(shí)現(xiàn)瀏覽器控制的核心是 “WebDriver + 瀏覽器驅(qū)動(dòng)” 的協(xié)作模式,流程如下:
      • 開發(fā)者編寫代碼:通過(guò) Python/Java 等語(yǔ)言調(diào)用 Selenium WebDriver 的 API(如 click()send_keys())。
      • WebDriver 轉(zhuǎn)發(fā)指令:WebDriver 將代碼中的操作指令(如 “點(diǎn)擊按鈕”)轉(zhuǎn)換為瀏覽器能識(shí)別的協(xié)議(如 W3C WebDriver 協(xié)議)。
      • 瀏覽器驅(qū)動(dòng)執(zhí)行:需提前安裝對(duì)應(yīng)瀏覽器的 “驅(qū)動(dòng)程序”(如 Chrome 對(duì)應(yīng) chromedriver),驅(qū)動(dòng)接收指令后,控制瀏覽器執(zhí)行具體操作。
      • 瀏覽器返回結(jié)果:操作結(jié)果(如頁(yè)面渲染、元素狀態(tài)變化)通過(guò)驅(qū)動(dòng)反饋給 WebDriver,最終可在代碼中獲取(如獲取頁(yè)面源碼、元素文本)。
      簡(jiǎn)單來(lái)說(shuō):代碼 → WebDriver → 瀏覽器驅(qū)動(dòng) → 瀏覽器,形成一套完整的 “指令下發(fā) - 執(zhí)行 - 反饋” 閉環(huán)。

      三、Selenium 關(guān)鍵特性

      • 多瀏覽器支持
        兼容主流瀏覽器,無(wú)需修改核心代碼,只需更換對(duì)應(yīng)的瀏覽器驅(qū)動(dòng)即可:
        • Chrome(需 chromedriver
        • Firefox(需 geckodriver
        • Edge(需 msedgedriver
        • Safari(macOS 自帶驅(qū)動(dòng),需手動(dòng)開啟)
      • 多編程語(yǔ)言支持
        提供豐富的語(yǔ)言綁定,開發(fā)者可使用熟悉的語(yǔ)言編寫腳本:
        • 主流語(yǔ)言:Python、Java、JavaScript(Node.js)、C#、Ruby
        • 小眾語(yǔ)言:Perl、PHP
      • 模擬真實(shí)用戶操作
        支持幾乎所有用戶在瀏覽器上的操作,覆蓋復(fù)雜交互場(chǎng)景:
        • 基礎(chǔ)操作:點(diǎn)擊click()、輸入文本send_keys()、清空內(nèi)容clear()、刷新頁(yè)面refresh()
        • 進(jìn)階操作:鼠標(biāo)懸停ActionChains、下拉滾動(dòng)execute_script() 執(zhí)行 JS)、切換窗口 /iframeswitch_to、處理彈窗alert
        • 等待機(jī)制:支持 “顯式等待”(等待特定元素加載完成)和 “隱式等待”(全局等待超時(shí)),解決頁(yè)面異步加載導(dǎo)致的元素定位失敗問(wèn)題。
      • 元素定位能力
        提供 8 種主流元素定位方式,可精準(zhǔn)定位頁(yè)面中的任何元素(如按鈕、輸入框、列表)
      定位方式語(yǔ)法(Python 示例)說(shuō)明(基于 HTML 屬性)
      ID 定位 driver.find_element(By.ID, "username") 通過(guò)元素的 id 屬性定位(唯一優(yōu)先)
      Name 定位 driver.find_element(By.NAME, "password") 通過(guò)元素的 name 屬性定位
      Class Name 定位 driver.find_element(By.CLASS_NAME, "btn") 通過(guò)元素的 class 屬性定位
      Tag Name 定位 driver.find_element(By.TAG_NAME, "input") 通過(guò) HTML 標(biāo)簽名定位(如 input
      Link Text 定位 driver.find_element(By.LINK_TEXT, "登錄") 定位超鏈接(完全匹配文本)
      Partial Link Text 定位 driver.find_element(By.PARTIAL_LINK_TEXT, "登") 定位超鏈接(模糊匹配文本)
      XPath 定位 driver.find_element(By.XPATH, "http://input[@id='username']") 基于 XML 路徑語(yǔ)法,支持復(fù)雜定位(最靈活)
      CSS Selector 定位 driver.find_element(By.CSS_SELECTOR, "#username") 基于 CSS 選擇器,定位效率比 XPath 高

      四、Python 環(huán)境下的 Selenium 基礎(chǔ)使用

      以最常用的 Python + Chrome 組合為例,演示核心流程:

      ①.環(huán)境準(zhǔn)備

      步驟 1:安裝 Selenium 庫(kù)

      通過(guò) pip 安裝 Python 版本的 Selenium:
      pip install selenium

      步驟 2:下載瀏覽器驅(qū)動(dòng)

        • 查看本地 Chrome 版本:打開 Chrome → 右上角三個(gè)點(diǎn) → 幫助 → 關(guān)于 Google Chrome(如版本 141.0.7390.54)。
        • 官方地址:ChromeDriver - WebDriver for Chrome
          (注意:驅(qū)動(dòng)版本需與 Chrome 版本完全匹配,或兼容匹配,否則無(wú)法啟動(dòng)瀏覽器)。
        • 配置驅(qū)動(dòng):將下載的 chromedriver.exe(Windows)或 chromedriver(macOS/Linux)放在 Python 安裝目錄,或添加到系統(tǒng)環(huán)境變量。

      image

      image

      ②. 基礎(chǔ)示例:打開網(wǎng)頁(yè)并操作

      下面代碼實(shí)現(xiàn) “打開百度 → 輸入關(guān)鍵詞 → 點(diǎn)擊搜索 → 獲取搜索結(jié)果” 的自動(dòng)化流程:
      #1.導(dǎo)包
      from selenium import webdriver
      import time
      from selenium.webdriver.common.by import By #定義類
      from selenium.webdriver.common.keys import Keys #定義鍵盤類
      web = webdriver.Chrome()
      web.maximize_window() #窗口最大化
      web.get('https://www.baidu.com/')
      print(web.title) #獲取百度網(wǎng)站標(biāo)題 百度一下,你就知道
      ipt = web.find_element(By.ID,"chat-textarea")
      ipt.send_keys('美女',Keys.ENTER) #自動(dòng)回車
      time.sleep(5)
      web.quit()
      #2.導(dǎo)包
      from selenium.webdriver import Chrome
      import time
      from selenium.webdriver.common.by import By #定義類
      from selenium.webdriver.common.keys import Keys #定義鍵盤類
      web = webdriver.Chrome()
      web.maximize_window() #窗口最大化
      web.get('https://www.baidu.com/')
      ipt = web.find_element(By.ID,"chat-textarea")
      ipt.send_keys('美女')
      web.find_element(By.ID,"chat-submit-button").click()#自動(dòng)點(diǎn)擊
      time.sleep(5)
      web.quit()

      ③.其它功能

      web.minimize_window()  # 窗口最小化
      web.set_window_size(1000, 500) #設(shè)置固定的窗口大小
      ipt = web.find_element(By.CLASS_NAME, 's_ipt')  # 如果需要用CLASS_NAME 需要注意 只適用于class值只有一個(gè)的情況
      ipt = web.find_element(By.XPATH, '//*[@id="chat-textarea"]') #Xpath正則表達(dá)式
      web.find_element(By.XPATH, '//div[@class="c-container"]').screenshot('截圖.png')  # screenshot截圖方法 傳參截圖存儲(chǔ)路徑
      web.save_screenshot('瀏覽器窗口.png')  # 截圖瀏覽器內(nèi)部窗口圖片
      ps = web.page_source  # 獲取元素面板的html結(jié)構(gòu)數(shù)據(jù)
      b = web.find_element(By.LINK_TEXT, '貼吧')  # 通過(guò)文本值去定位 文本值需要是標(biāo)簽里面的全部文本
      print(b.text)  # 獲取標(biāo)簽文本內(nèi)容
      print(b.get_attribute('href'))  # 獲取屬性值 傳參屬性名
      print(b.location)  # 獲取標(biāo)簽左上角點(diǎn)相對(duì)于瀏覽器窗口原點(diǎn)的 坐標(biāo)  {'x': 191, 'y': 19}
      print(b.size)  # 標(biāo)簽寬高尺寸  {'height': 23, 'width': 26}
      b = web.find_element(By.PARTIAL_LINK_TEXT, '')  # 通過(guò)文本值去定位 文本值可以是部分文本
      # print(b)

      ④.規(guī)避檢測(cè)

      from selenium import webdriver
      from selenium.webdriver.common.by import By  # 定位類
      import time
      
      web = webdriver.Chrome() # 實(shí)例化瀏覽器對(duì)象
      web.maximize_window()  # 窗口最大化
      web.implicitly_wait(3)  # 隱式等待  輪詢
      web.get('https://antispider1.scrape.center/')
      time.sleep(1900)
      web.quit()  # 關(guān)閉瀏覽器

      顯示結(jié)果:

      image

       添加規(guī)避檢測(cè)代碼后會(huì)正常顯示

      from selenium import webdriver
      from selenium.webdriver.common.by import By  # 定位類
      import time
      
      web = webdriver.Chrome() # 實(shí)例化瀏覽器對(duì)象
      web.maximize_window()  # 窗口最大化
      web.implicitly_wait(3)  # 隱式等待  輪詢
      web.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
                   "source": """
                   Object.defineProperty(navigator, 'webdriver', {
                   get: () => false
                   })"""
               })  # 規(guī)避檢測(cè)  當(dāng)獲取navigator下面的webdriver的時(shí)候 篡改為false
      web.get('https://antispider1.scrape.center/')
      time.sleep(1900)
      web.quit()  # 關(guān)閉瀏覽器

      image

       ⑤.瀏覽器自動(dòng)關(guān)閉與保持打開的3種方案

      from selenium import webdriver
      from selenium.webdriver.chrome.options import Options  # 用于detach配置
      import time
      # ==============================
      # 方案1:固定時(shí)間等待(腳本暫停N秒后關(guān)閉,適合自動(dòng)測(cè)試)
      # ==============================
      print("=== 運(yùn)行方案1:固定時(shí)間等待 ===")
      # 初始化瀏覽器
      web1 = webdriver.Chrome()
      web1.maximize_window()
      web1.get('https://www.baidu.com/')
      # 關(guān)鍵:固定等待10秒(可修改數(shù)字調(diào)整等待時(shí)長(zhǎng))
      time.sleep(10)
      # 等待結(jié)束后關(guān)閉當(dāng)前瀏覽器(避免多窗口干擾)
      web1.quit()
      print("方案1執(zhí)行完畢,瀏覽器已關(guān)閉\n")
      
      # ==============================
      # 方案2:用戶輸入等待(按回車鍵才關(guān)閉,適合手動(dòng)操作瀏覽器)
      # ==============================
      print("=== 運(yùn)行方案2:用戶輸入等待 ===")
      # 初始化瀏覽器
      web2 = webdriver.Chrome()
      web2.maximize_window()
      web2.get('https://www.baidu.com/')
      # 關(guān)鍵:等待用戶在控制臺(tái)按回車鍵(按前瀏覽器保持打開)
      input("方案2提示:請(qǐng)?jiān)诳刂婆_(tái)按【回車鍵】關(guān)閉瀏覽器...")
      # 用戶按回車后關(guān)閉瀏覽器
      web2.quit()
      print("方案2執(zhí)行完畢,瀏覽器已關(guān)閉\n")
      
      # ==============================
      # 方案3:detach配置(腳本結(jié)束后瀏覽器仍保持打開,需手動(dòng)關(guān)閉)
      # ==============================
      print("=== 運(yùn)行方案3:detach配置(瀏覽器將保持打開) ===")
      # 1. 創(chuàng)建Chrome配置對(duì)象,添加“進(jìn)程分離”參數(shù)
      chrome_options = Options()
      chrome_options.add_experimental_option("detach", True)  # 核心配置:瀏覽器不隨腳本關(guān)閉
      # 2. 初始化瀏覽器時(shí)傳入配置
      web3 = webdriver.Chrome(options=chrome_options)
      web3.maximize_window()
      web3.get('https://www.baidu.com/')
      print("方案3執(zhí)行完畢,瀏覽器已啟動(dòng)(需手動(dòng)點(diǎn)擊窗口右上角關(guān)閉)")

      五、Selenium 的應(yīng)用場(chǎng)景

      • Web 自動(dòng)化測(cè)試
        這是 Selenium 的核心場(chǎng)景:開發(fā)者 / 測(cè)試工程師編寫腳本,自動(dòng)驗(yàn)證 Web 應(yīng)用的功能(如登錄、支付、表單提交),替代人工測(cè)試,提高效率并減少重復(fù)工作。例如:驗(yàn)證 “用戶輸入錯(cuò)誤密碼時(shí),登錄按鈕是否提示錯(cuò)誤”。
      • 合規(guī)網(wǎng)絡(luò)爬蟲
        對(duì)于動(dòng)態(tài)渲染的網(wǎng)頁(yè)(如 JavaScript 加載的內(nèi)容,普通爬蟲無(wú)法獲取),Selenium 可模擬瀏覽器加載完整頁(yè)面,再提取數(shù)據(jù)。注意:需遵守網(wǎng)站的 robots.txt 協(xié)議,避免非法爬取。
      • 瀏覽器自動(dòng)化操作
        • 自動(dòng)填寫重復(fù)性表單(如每日打卡、報(bào)表提交);
        • 自動(dòng)監(jiān)控網(wǎng)頁(yè)內(nèi)容變化(如商品價(jià)格、公告更新);
        • 批量執(zhí)行瀏覽器操作(如批量下載文件、批量截圖)。

      六、常見(jiàn)問(wèn)題與注意事項(xiàng)

      ①.驅(qū)動(dòng)版本不匹配
      報(bào)錯(cuò)表現(xiàn):SessionNotCreatedException
      解決:確保瀏覽器版本與驅(qū)動(dòng)版本完全一致(或查看驅(qū)動(dòng)官網(wǎng)的 “兼容版本說(shuō)明”)。

      ②.元素定位失敗
      常見(jiàn)原因:

      • 頁(yè)面未加載完成就定位元素:使用 “顯式等待”(WebDriverWait)替代 “強(qiáng)制等待”(time.sleep());
      • 元素在 iframe 中:需先通過(guò) driver.switch_to.frame(iframe元素) 切換到 iframe,再定位元素;
      在 Selenium 中切換 iframe(內(nèi)嵌框架)是處理嵌套頁(yè)面元素的常見(jiàn)操作,主要通過(guò)以下幾種方法實(shí)現(xiàn),核心是使用switch_to.frame()方法:

      ?.通過(guò)iframeidname切換(最常用)

      如果 iframe 有唯一的idname屬性,直接傳入該屬性值即可:
      from selenium import webdriver
      
      web = webdriver.Chrome()
      web.get("目標(biāo)頁(yè)面URL")
      
      # 通過(guò)id切換
      web.switch_to.frame("iframe_id")
      
      # 或通過(guò)name切換
      web.switch_to.frame("iframe_name")

      ?. 通過(guò)WebElement對(duì)象切換(推薦)

      先定位到 iframe 元素,再傳入該元素對(duì)象(適用于無(wú) id/name 或?qū)傩圆晃ㄒ坏那闆r):
      # 先定位iframe元素(可用xpath、css selector等)
      iframe_element = web.find_element(By.XPATH, "//iframe[@class='xxx']")
      
      # 切換到該iframe
      web.switch_to.frame(iframe_element)

      ?. 通過(guò)索引切換(不推薦,易變)

      如果 iframe 在頁(yè)面中的位置固定,可通過(guò)索引(從0開始)切換(不推薦,因頁(yè)面結(jié)構(gòu)變化可能導(dǎo)致索引失效):
      # 切換到第1個(gè)iframe(索引0)
      web.switch_to.frame(0)

      ?. 切換回主文檔(重要)

      操作完 iframe 內(nèi)的元素后,需切換回主頁(yè)面,否則無(wú)法操作主文檔的元素:
      # 切回主文檔
      web.switch_to.default_content()

      ?. 切換到父級(jí) iframe(多層嵌套時(shí))

      如果 iframe 嵌套在另一個(gè) iframe 內(nèi),可通過(guò)以下方法返回上一級(jí) iframe
      # 切換到父級(jí)iframe
      web.switch_to.parent_frame()

      注意事項(xiàng):

        • 切換前確保 iframe 已加載完成,可配合WebDriverWait等待 iframe 出現(xiàn):

      from selenium.webdriver.support.ui import WebDriverWait
      from selenium.webdriver.support import expected_conditions as EC
      
      # 等待iframe加載并切換
      WebDriverWait(driver, 10).until(
          EC.frame_to_be_available_and_switch_to_it((By.ID, "iframe_id"))
      )
        • iframe 是動(dòng)態(tài)生成的(如id帶隨機(jī)值),優(yōu)先用WebElement方法定位(通過(guò)其他穩(wěn)定屬性,如classsrc等)。
      • 元素是動(dòng)態(tài)生成的(如點(diǎn)擊后才出現(xiàn)):確保操作順序正確,先觸發(fā)元素生成,再定位。

      ③.瀏覽器無(wú)頭模式
      若不需要可視化瀏覽器窗口(如服務(wù)器環(huán)境),可開啟 “無(wú)頭模式”(Headless),減少資源占用:

      from selenium.webdriver.chrome.options import Options
      
      chrome_options = Options()
      chrome_options.add_argument("--headless=new")  # 開啟無(wú)頭模式(Chrome 112+ 推薦)
      driver = webdriver.Chrome(options=chrome_options)

      七、Selenium 與其他工具的對(duì)比

      工具核心優(yōu)勢(shì)核心劣勢(shì)適用場(chǎng)景
      Selenium 模擬真實(shí)瀏覽器,支持復(fù)雜交互,多語(yǔ)言 / 瀏覽器 資源占用高,速度較慢 動(dòng)態(tài)頁(yè)面、復(fù)雜交互(測(cè)試 / 爬蟲)
      BeautifulSoup 輕量,解析 HTML 速度快 無(wú)法處理 JavaScript 動(dòng)態(tài)內(nèi)容,無(wú)自動(dòng)化能力 靜態(tài)頁(yè)面數(shù)據(jù)提取
      Playwright 微軟開發(fā),內(nèi)置驅(qū)動(dòng)(無(wú)需手動(dòng)下載),速度快 生態(tài)不如 Selenium 成熟 新一代 Web 自動(dòng)化(替代 Selenium 的選擇)
      總之,SeleniumWeb 自動(dòng)化領(lǐng)域的 “瑞士軍刀”,靈活性高、功能全面,尤其適合需要模擬真實(shí)用戶交互的場(chǎng)景。掌握它需要熟悉 “元素定位”“等待機(jī)制” 這兩個(gè)核心點(diǎn),再結(jié)合具體場(chǎng)景擴(kuò)展即可。
      Beautiful Soup(簡(jiǎn)稱 BS4)爬蟲
      BS4是 Python 中一個(gè)強(qiáng)大的 HTML 和 XML 解析庫(kù),它能夠從網(wǎng)頁(yè)中提取數(shù)據(jù),處理不規(guī)范標(biāo)記(“-tag soup”),并將復(fù)雜的 HTML 文檔轉(zhuǎn)換為一個(gè)易于遍歷的樹形結(jié)構(gòu),方便開發(fā)者快速定位和提取所需信息。

      核心功能

      1. 解析 HTML/XML 文檔
        支持多種解析器(如 Python 內(nèi)置的 html.parserlxmlhtml5lib 等),能處理不完整或格式混亂的標(biāo)記。
      2. 遍歷和搜索節(jié)點(diǎn)
        提供直觀的 API 用于查找、遍歷 HTML 元素(如標(biāo)簽、屬性、文本)。
      3. 修改文檔結(jié)構(gòu)
        支持添加、刪除、修改標(biāo)簽或?qū)傩浴?/div>
       BS4的安裝方法:
      pip install beautifulsoup4

      通常搭配解析器 lxml(速度快,支持 XML)或 html5lib(兼容性好)使用:

      pip install lxml  # 推薦
      #
      pip install html5lib

      實(shí)例化Beautiful Soup對(duì)象:

      #導(dǎo)包
      from bs4 import BeautifulSoup
      # 解析字符串#本地Html文檔加載
      #將此Html文檔保存為Html文件到本地
      """
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>測(cè)試BS4</title>
      </head>
      <body>
      <div>
          <p>百里守約</p>
      </div>
      <div class="song">
          <p>李清照</p>
          <p>王安石</p>
          <p>蘇軾</p>
          <p>柳宗元</p>
        <a  title="趙匡胤" target="_self">
          <span>this is span </span>
          宋朝是最強(qiáng)大的王朝,不是軍隊(duì)的強(qiáng)大,而是經(jīng)濟(jì)很強(qiáng)大,國(guó)民都很有錢</a>
        <a href="" class="du">總為浮動(dòng)能蔽日,長(zhǎng)安不見(jiàn)使人愁</a>
        <img src="http://baidu.com/meiny.jpg" alt=""/>
      </div>
      <div class="tang">
      <ul>
        <li><a  title="qing">清明時(shí)節(jié)雨紛紛,路上行人欲斷魂,借問(wèn)酒家何處有,牧童遙指杏花村</a></li>
        <li><a  title="qin">秦時(shí)明月漢時(shí)關(guān),萬(wàn)里長(zhǎng)征人未還,但使龍城飛將在,不叫胡馬度陰山</a></li>
        <li><a  title="qi">岐王宅里尋常見(jiàn),崔九堂前幾度聞,正是江南好風(fēng)景,落花時(shí)節(jié)又逢春</a></li>
        <li><a  title="du">杜甫</a></li>
        <li><a  title="du">杜牧</a></li>
      <li><b>杜小月/b></li>
      <li><i>度蜜月</i></li>
       <li><a  id="feng">鳳凰臺(tái)上鳳凰游,鳳去臺(tái)空江自流,吳空花草埋幽徑,晉代衣冠成古丘</a></li>
      </ul>
      </div>
      </body>
      </html>
       """ 
      with open(r"E:\Python code\cls32爬蟲\BS4\BS4.html", "r", encoding="utf-8") as fp: 
      soup = BeautifulSoup(fp, 'lxml') print(soup)

      定位查找解析標(biāo)簽和屬性的方法:

      print(soup.div)#標(biāo)簽定位
      print(soup.find('div',class_ = 'tang')) """標(biāo)簽和屬性的定位查找 
      class是Python中的關(guān)鍵字,不能直接作為參數(shù)名使用。在Beautiful Soup 中,當(dāng)需要按類名查找元素時(shí),應(yīng)該使用class_(后面加一個(gè)下劃線)來(lái)代替class
      """
      print(soup.find_all('a')) #定位查找所有包含的標(biāo)簽,返回的是列表。
      print(soup.select('.tang'))#選擇器定位查找。
      print(soup.select('.tang > ul > li > a')[0])#選擇器層級(jí)定位查找 >表示的是一個(gè)層級(jí)
      print(soup.select('.tang > ul a')[0])#選擇器層級(jí)定位查找 空格表示的是多個(gè)層級(jí),也就是跨層級(jí)

      獲取標(biāo)簽之間的文本數(shù)據(jù)

      print(soup.a.text) #
      print(soup.a.get_text()) #可以獲取某個(gè)標(biāo)簽中所有的文本內(nèi)容
      print(soup.a.string) #只可以獲取該標(biāo)簽下真系的文本內(nèi)容
      print(soup.select('.tang > ul > li a')[0]['href']) #獲取標(biāo)簽中的屬性值的文本內(nèi)容

       

       

       
       
       
       
       
       

        

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

      ?

      posted @ 2025-05-12 10:19  自學(xué)小天才  閱讀(65)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 久久人人爽人人爽人人av| 依依成人精品视频在线观看 | 亚洲的天堂在线中文字幕| 成熟少妇XXXXX高清视频| 治县。| 亚洲精品一区二区三区大| 精品一区二区三区不卡| 久久a级片| 无码人妻久久一区二区三区app| 日韩人妻av一区二区三区| 少妇被粗大的猛烈进出69影院一| 开心色怡人综合网站| 午夜精品极品粉嫩国产尤物| 巫溪县| 宝贝腿开大点我添添公视频免| 亚洲中文字幕一区二区| 人妻少妇456在线视频| 精品无码av无码免费专区| 免费人妻av无码专区| 国产午夜福利视频在线| 永靖县| 在线免费观看毛片av| 久久不见久久见免费视频观看| 无码人妻精品一区二区三区下载| 亚洲中文字幕一区精品自| 亚洲国产美女精品久久久 | 精品av综合导航| 中文日产幕无线码一区中文| 婷婷色爱区综合五月激情韩国| 呼伦贝尔市| jk白丝喷浆| 天堂mv在线mv免费mv香蕉 | www插插插无码免费视频网站| 国产精品一区二区色综合| 国产婷婷综合在线视频中文| 国产在线观看免费观看| 国产色无码专区在线观看 | 四虎成人免费视频在线播放| 偏关县| 欧美一区二区三区欧美日韩亚洲 | 广饶县|