天天看點

從零開始學python(十二)如何成為一名優秀的爬蟲工程師

作者:天天不吃飯阿

前言

回顧之前講述了python文法程式設計 必修入門基礎和網絡程式設計,多線程/多程序/協程等方面的内容,後續講到了資料庫程式設計篇MySQL,Redis,MongoDB篇,和機器學習,全棧開發,資料分析前面沒看的也不用往前翻,系列文已經整理好了:

從零開始學python(十二)如何成為一名優秀的爬蟲工程師

1.跟我一起從零開始學python(一)程式設計文法必修

2.跟我一起從零開始學python(二)網絡程式設計

3.跟我一起從零開始學python(三)多線程/多程序/協程

4.跟我一起從零開始學python(四)資料庫程式設計:MySQL資料庫

5.跟我一起從零開始學python(五)資料庫程式設計:Redis資料庫

6.跟我一起從零開始學python(六)資料庫程式設計:MongoDB資料庫

7.跟我一起從零開始學python(七)機器學習

8.跟我一起從零開始學python(八)全棧開發

9.跟我一起從零開始學python(九)資料分析

10.跟我一起從零開始學python(十)Hadoop從零開始入門

11.跟我一起從零開始學python(十一)簡述spark

從零開始學python(十二)如何成為一名優秀的爬蟲工程師

适用于零基礎學習和進階人群的python資源:

① 騰訊認證python完整項目實戰教程筆記PDF

② 十幾個大廠python面試專題PDF

③ python全套視訊教程(零基礎-進階進階JS逆向)

④ 百個項目實戰+源碼+筆記

⑤ 程式設計文法-機器學習-全棧開發-資料分析-爬蟲-APP逆向等全套項目+文檔

python教程+源碼+學習筆記

本系列文根據以下學習路線展開講述,由于内容較多:

從零開始學python(十二)如何成為一名優秀的爬蟲工程師

一丶采集功底專題

1.網絡請求

網絡請求是爬蟲工程師采集資料的重要手段之一。在PC端爬蟲中,網絡請求通常使用HTTP協定進行通信,通過發送HTTP請求擷取目标網站的資料。

爬蟲工程師需要掌握HTTP協定的基本知識,包括HTTP請求和響應的格式、常見的HTTP請求方法(如GET、POST等)、HTTP請求頭和響應頭的常見字段等。

在進行網絡請求時,爬蟲工程師通常使用HTTP用戶端庫,如Python中的requests庫、Java中的HttpClient等。這些庫封裝了HTTP協定的細節,提供了簡單易用的API,友善爬蟲工程師進行網絡請求。

爬蟲工程師還需要了解一些反爬蟲技術,如User-Agent僞裝、IP代理等,以應對目标網站的反爬蟲政策。

從零開始學python(十二)如何成為一名優秀的爬蟲工程師

一丶requests

1.requests源碼解析

對于爬蟲工程師來說,網絡請求是常用的資料采集方式之一。而Python的requests庫,作為一個高效且易用的HTTP請求庫,被爬蟲工程師廣泛使用。在深入學習requests庫前,建議先了解下其中的源碼實作。

requests庫是基于urllib3庫封裝的,是以在使用requests庫時需要先安裝對應的依賴庫urllib3。

接下來,我們通過分析requests庫的源代碼,來了解其中的一些實作細節。

首先是發送請求的實作,即requests庫中的Request類。Request類用于封裝發送請求的參數,并通過一個Session對象發送請求并傳回響應。以下是Request類的核心代碼:

class Request:

    @staticmethod
    def send(session, method, url, **kwargs):
        # ...
        resp = session.request(method=method, url=url, **kwargs)
        return resp           

我們可以看到,Request類中的send方法調用了Session對象的request方法,這個方法是整個庫中負責發送請求和傳回響應的核心方法。以下是Session類中request方法的核心代碼:

class Session:

    def request(self, method, url, params=None, data=None, headers=None, cookies=None, files=None, auth=None,
                timeout=None, allow_redirects=True, proxies=None, hooks=None, stream=None, verify=None, cert=None,
                json=None):            
        # ...
        return self.send(prep, **send_kwargs)           

我們可以看到,Session對象的request方法的參數和關鍵字參數與HTTP請求的相關部分一一對應,其中最重要的是prep參數(即經過預處理的Request對象),它包含了請求的相關資訊,如請求方法,請求頭,請求體等。Session對象的request方法最終調用了self.send方法,即發送HTTP請求并傳回響應。

requests庫實作了帶有各種HTTP請求方法的函數接口,如requests.get()、requests.post()等,這些接口在内部會自動建立一個Session對象,然後調用Session對象的request方法,進而傳回請求響應。

總體來說,requests是一個功能強大的HTTP請求庫,它的源代碼實作清晰、易于閱讀和了解,掌握其中的實作細節可以幫助我們更好的使用這個庫。

2.requests常用方法

requests是一個Python第三方庫,用于發送HTTP請求。以下是requests常用方法:

  • requests.get(url, params=None, **kwargs):發送GET請求,url為請求的URL位址,params為請求參數,kwargs為其他可選參數。
  • requests.post(url, data=None, json=None, **kwargs):發送POST請求,url為請求的URL位址,data為請求資料,json為請求的JSON資料,**kwargs為其他可選參數。
  • requests.put(url, data=None, **kwargs):發送PUT請求,url為請求的URL位址,data為請求資料,**kwargs為其他可選參數。
  • requests.delete(url, **kwargs):發送DELETE請求,url為請求的URL位址,**kwargs為其他可選參數。
  • requests.head(url, **kwargs):發送HEAD請求,url為請求的URL位址,**kwargs為其他可選參數。
  • requests.options(url, **kwargs):發送OPTIONS請求,url為請求的URL位址,**kwargs為其他可選參數。
  • requests.request(method, url, **kwargs):發送自定義請求,method為請求方法,url為請求的URL位址,**kwargs為其他可選參數。
  • requests.session():建立一個Session對象,用于保持會話狀态。
  • requests.get(url, headers=headers):發送GET請求,并設定請求頭。
  • requests.get(url, cookies=cookies):發送GET請求,并設定請求的Cookies。
  • requests.get(url, proxies=proxies):發送GET請求,并設定代理伺服器。
  • requests.get(url, timeout=timeout):發送GET請求,并設定逾時時間。
  • requests.get(url, verify=verify):發送GET請求,并設定SSL證書驗證。
  • requests.get(url, allow_redirects=allow_redirects):發送GET請求,并設定是否允許重定向。
  • requests.get(url, stream=stream):發送GET請求,并設定是否使用流式傳輸

3.data/json/param參數傳遞

在使用requests庫發送網絡請求時,我們可以通過傳遞不同的參數來實作不同的請求方式和資料傳遞方式。常用的參數包括data、json和params。

1.data參數

data參數用于傳遞表單資料,通常用于POST請求。它可以是一個字典,也可以是一個字元串。如果是字典,requests會自動将其轉換為表單形式;如果是字元串,則需要手動指定Content-Type為application/x-www-form-urlencoded。

示例代碼:

import requests

data = {
    'username': 'admin',
    'password': '123456'
}

response = requests.post('http://www.example.com/login', data=data)           

2.json參數

json參數用于傳遞JSON格式的資料,通常用于POST請求。它可以是一個字典,也可以是一個字元串。如果是字典,requests會自動将其轉換為JSON格式;如果是字元串,則需要手動指定Content-Type為application/json。

示例代碼:

import requests

data = {
    'username': 'admin',
    'password': '123456'
}

response = requests.post('http://www.example.com/login', json=data)           

3.params參數

params參數用于傳遞URL參數,通常用于GET請求。它可以是一個字典,也可以是一個字元串。如果是字典,requests會自動将其轉換為URL參數;如果是字元串,則需要手動拼接URL。

示例代碼:

import requests

params = {
    'page': 1,
    'size': 10
}

response = requests.get('http://www.example.com/articles', params=params)           

4.隧道代理使用

隧道代理是一種通過隧道連接配接到代理伺服器的方式來進行網絡請求的方法。這種方式可以幫助我們隐藏真實的IP位址,提高爬蟲的穩定性和安全性。

使用隧道代理需要先購買代理服務,然後在代碼中設定代理伺服器的IP位址和端口号。以下是一個使用隧道代理的示例代碼:

import requests

proxy = {
    'http': 'http://代理伺服器IP位址:端口号',
    'https': 'https://代理伺服器IP位址:端口号'
}

url = 'https://www.example.com'
response = requests.get(url, proxies=proxy)

print(response.text)           

在上面的代碼中,我們首先定義了一個代理字典,包含了http和https兩種協定的代理伺服器位址和端口号。然後使用requests庫的get方法發送請求時,将代理字典作為proxies參數傳入即可。

需要注意的是,使用隧道代理可能會降低請求速度,而且代理服務的品質也會影響到爬蟲的效果。是以,在選擇代理服務時需要謹慎,建議選擇穩定可靠的服務商。

5.證書異常處理

在進行網絡請求時,有些網站會進行證書認證以確定資料的安全。如果requests庫在進行SSL證書驗證時遇到了問題,會抛出“證書驗證異常(Certificate Verification Error)”的異常。這個異常通常是由于請求響應的SSL證書無效或不受信任導緻的。

以下是requests庫中處理證書異常的方法:

1.忽略證書驗證

在使用requests庫進行網絡請求時,可以通過設定verify參數為False來忽略SSL證書驗證。這個方法會禁止requests庫對證書進行驗證,而是采用不安全的方式進行通信,是以在進行敏感操作時應慎重使用。

例如:

response = requests.get('https://example.com', verify=False)           

2.設定證書檔案

可以通過設定cert參數來指定一個證書檔案,在請求時使用該證書進行驗證。這個方法需要事先獲得一個有效的證書檔案,如果無法提供有效證書則無法進行安全通信。

例如:

response = requests.get('https://example.com', cert=('path/to/cert.crt', 'path/to/key'))           

3.添加自定義證書

可以通過requests庫提供的certifi庫在運作時初始化一個自定義證書,進而進行證書驗證。這種方式需要提供證書的SHA256指紋值,并将其添加到requests庫已有的證書清單中。

例如:

import certifi

cert = certifi.where()
fingerprints = {'example.com': 'A1:B2:C3:...', ...}
with open(cert, 'a') as f:
    for host, fingerprint in fingerprints.items():
        f.write(f'{host} {fingerprint}\n')

response = requests.get('https://example.com', verify=True)           

在以上代碼中,certifi.where()用于擷取目前Python環境中的證書路徑,然後将每個需要驗證的主機和其證書的SHA256指紋添加到證書檔案中。

綜上,要避免證書異常需要注意常見的安全規則,如設定SSL證書驗證、使用CA頒發的證書、對外不開放不安全的通信端口等。需要快速掃描裝置,確定元件更新到最新版本,在安全上下文中測試企業所依賴的所有服務并采用有力的加密技術以支援加密通信。

二丶httpx

1.httpx源碼解析

httpx是一個Python異步HTTP用戶端庫,它提供了簡單易用的API,支援異步和同步請求,支援HTTP/1.1和HTTP/2協定,支援代理、SSL/TLS、Cookie等功能。下面我們來看一下httpx的源碼解析。

httpx的核心代碼在client.py檔案中,其中最重要的是Client類。Client類是httpx的主要接口,它提供了發送HTTP請求的方法,如get、post、put、delete等。下面是Client類的定義:

class Client:
    def __init__(
        self,
        timeout=UNSET,
        follow_redirects=UNSET,
        max_redirects=UNSET,
        verify=UNSET,
        cert=UNSET,
        trust_env=UNSET,
        http2=UNSET,
        backend=UNSET,
        default_headers=UNSET,
        base_url=UNSET,
        app=UNSET,
        auth=UNSET,
        cookies=UNSET,
        allow_redirects=UNSET,
        proxies=UNSET,
        dispatch=UNSET,
        limits=UNSET,
        pool_limits=UNSET,
        retry=UNSET,
        trust_env_proxies=UNSET,
        headers=UNSET,
        **extra_options,
    ):
        ...           

Client類的構造函數接受很多參數,這些參數可以用來配置httpx的行為。其中比較重要的參數包括:

  • timeout:請求逾時時間。
  • follow_redirects:是否自動跟随重定向。
  • max_redirects:最大重定向次數。
  • verify:是否驗證SSL證書。
  • cert:用戶端證書。
  • trust_env:是否信任環境變量。
  • http2:是否啟用HTTP/2協定。
  • backend:HTTP用戶端後端。
  • default_headers:預設請求頭。
  • base_url:基礎URL。
  • app:ASGI應用程式。
  • auth:HTTP認證。
  • cookies:請求Cookie。
  • allow_redirects:是否允許重定向。
  • proxies:代理伺服器。
  • dispatch:請求分發器。
  • limits:請求限制。
  • pool_limits:連接配接池限制。
  • retry:請求重試。
  • trust_env_proxies:是否信任環境變量中的代理伺服器。
  • headers:請求頭。

Client類的方法包括:

  • request:發送HTTP請求。
  • get:發送GET請求。
  • post:發送POST請求。
  • put:發送PUT請求。
  • delete:發送DELETE請求。
  • head:發送HEAD請求。
  • options:發送OPTIONS請求。
  • patch:發送PATCH請求。 這些方法都是基于request方法實作的,隻是參數不同。下面是request方法的定義:
async def request(
    self,
    method,
    url,
    *,
    params=UNSET,
    data=UNSET,
    json=UNSET,
    headers=UNSET,
    cookies=UNSET,
    files=UNSET,
    auth=UNSET,
    timeout=UNSET,
    allow_redirects=UNSET,
    cert=UNSET,
    verify=UNSET,
    stream=UNSET,
    trust_env=UNSET,
    max_redirects=UNSET,
    http2=UNSET,
    backend=UNSET,
    dispatch=UNSET,
    limits=UNSET,
    pool_limits=UNSET,
    retry=UNSET,
    trust_env_proxies=UNSET,
    **options,
):
    ...           

request方法接受很多參數,包括HTTP請求方法、URL、請求參數、請求體、請求頭、請求Cookie、檔案、HTTP認證、請求逾時時間、是否允許重定向、用戶端證書、是否驗證SSL證書、是否使用流式傳輸、是否信任環境變量、最大重定向次數、是否啟用HTTP/2協定、HTTP用戶端後端、請求分發器、請求限制、連接配接池限制、請求重試、是否信任環境變量中的代理伺服器等。

httpx的源碼比較清晰,代碼結構清晰,注釋詳細,易于閱讀和了解。如果你想深入了解httpx的實作原理,可以閱讀httpx的源碼。

2.httpx常用方法

httpx是一個Python的異步HTTP用戶端庫,它提供了許多常用的方法來發送HTTP請求和處理響應。以下是httpx常用的方法:

  • get(url, params=None, **kwargs): 發送GET請求,url為請求的URL,params為請求參數,kwargs為其他可選參數,如headers、timeout等。
  • post(url, data=None, json=None, **kwargs): 發送POST請求,url為請求的URL,data為請求資料,json為請求的JSON資料,kwargs為其他可選參數,如headers、timeout等。
  • put(url, data=None, **kwargs): 發送PUT請求,url為請求的URL,data為請求資料,kwargs為其他可選參數,如headers、timeout等。
  • delete(url, **kwargs): 發送DELETE請求,url為請求的URL,kwargs為其他可選參數,如headers、timeout等。
  • head(url, **kwargs): 發送HEAD請求,url為請求的URL,kwargs為其他可選參數,如headers、timeout等。
  • options(url, **kwargs): 發送OPTIONS請求,url為請求的URL,kwargs為其他可選參數,如headers、timeout等。
  • request(method, url, **kwargs): 發送自定義請求,method為請求方法,url為請求的URL,kwargs為其他可選參數,如headers、timeout等。
  • close(): 關閉httpx用戶端。
  • request_stream(method, url, **kwargs): 發送流式請求,method為請求方法,url為請求的URL,kwargs為其他可選參數,如headers、timeout等。
  • request_raw(method, url, **kwargs): 發送原始請求,method為請求方法,url為請求的URL,kwargs為其他可選參數,如headers、timeout等。
  • request_bytes(method, url, **kwargs): 發送位元組請求,method為請求方法,url為請求的URL,kwargs為其他可選參數,如headers、timeout等。
  • request_json(method, url, **kwargs): 發送JSON請求,method為請求方法,url為請求的URL,kwargs為其他可選參數,如headers、timeout等。
  • request_text(method, url, **kwargs): 發送文本請求,method為請求方法,url為請求的URL,kwargs為其他可選參數,如headers、timeout等。
  • request_files(method, url, files=None, **kwargs): 發送檔案請求,method為請求方法,url為請求的URL,files為上傳的檔案,kwargs為其他可選參數,如headers、timeout等。
  • request_multipart(method, url, data=None, files=None, **kwargs): 發送多部分請求,method為請求方法,url為請求的URL,data為請求資料,files為上傳的檔案,kwargs為其他可選參數,如headers、timeout等。

3.httpx上下文處理

在httpx中,上下文處理是指在一個請求中,将一些共同的參數或配置資訊儲存在一個上下文對象中,以便在後續的請求中使用。這樣可以避免在每個請求中都重複設定相同的參數或配置資訊,提高代碼的可讀性和可維護性。

httpx中的上下文對象是一個字典,可以通過建立一個httpx.Context對象來擷取。在建立Context對象時,可以傳入一些預設的參數或配置資訊,這些資訊會被儲存在Context對象中,以便在後續的請求中使用。

下面是一些常用的httpx上下文處理方法:

1.建立Context對象

import httpx

context = httpx.Context()           

2.設定預設的請求頭

context.headers.update({
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
})           

3.設定代理

context.proxies = {
    'http': 'http://127.0.0.1:8888',
    'https': 'http://127.0.0.1:8888'
}           

4.設定逾時時間

context.timeout = httpx.Timeout(10.0, read=20.0)           

5.設定SSL驗證

context.verify = False           

6.設定cookie

context.cookies['name'] = 'value'           

7.設定認證資訊

context.auth = httpx.BasicAuth('username', 'password')           

8.設定重試次數

context.retry = httpx.Retry(total=3, backoff_factor=0.3)           

9.設定連接配接池

context.http2 = True
context.max_keepalive_connections = 100
context.max_connections = 100           

10.在請求中使用Context對象

import httpx

context = httpx.Context()
context.headers.update({
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
})

with httpx.Client(context=context) as client:
    response = client.get('https://www.example.com')           

4.httpx異步請求

在進行網絡請求時,有時候需要進行異步請求,以提高效率和性能。httpx是一個支援異步請求的Python HTTP用戶端庫,可以使用async/await文法進行異步請求。

下面是一個使用httpx進行異步請求的示例:

import httpx
import asyncio

async def fetch(url):
    async with httpx.AsyncClient() as client:
        response = await client.get(url)
        return response.text

async def main():
    urls = [
        'https://www.baidu.com',
        'https://www.google.com',
        'https://www.bing.com'
    ]
    tasks = [asyncio.create_task(fetch(url)) for url in urls]
    results = await asyncio.gather(*tasks)
    print(results)

if __name__ == '__main__':
    asyncio.run(main())           

在上面的示例中,我們定義了一個fetch函數,用于異步請求指定的URL,并傳回響應内容。然後在main函數中,我們定義了三個URL,使用asyncio.create_task建立了三個異步任務,并使用asyncio.gather等待所有任務完成,并列印結果。

需要注意的是,在使用httpx進行異步請求時,需要使用AsyncClient類,而不是普通的Client類。此外,需要使用async/await文法進行異步請求。

2.資料解析

資料解析是爬蟲工程師采集資料的重要環節,它的目的是從爬取到的網頁中提取出需要的資料。常用的資料解析方法有正規表達式、XPath、BeautifulSoup等。

其中,正規表達式是一種強大的文本比對工具,可以用來比對和提取文本中的特定模式。在爬蟲中,正規表達式通常用于比對HTML标簽中的内容,例如比對網頁中的标題、連結、圖檔等。

正規表達式的基本文法包括字元集、量詞、分組、反向引用等。例如,要比對一個HTML标簽中的連結,可以使用以下正規表達式:

<a\s+href=["']([^"']+)["'].*?>           

其中,\s+表示比對一個或多個空格,["']表示比對單引号或雙引号,[^"']+表示比對除了單引号和雙引号以外的任意字元,.*?表示比對任意字元,但是盡可能少地比對。

在使用正規表達式進行資料解析時,需要注意以下幾點:

  • 正規表達式的文法較為複雜,需要仔細學習和了解。
  • 正規表達式的性能較差,對于大規模資料解析可能會影響爬蟲的效率。
  • 正規表達式隻能比對文本,對于非文本資料(如圖檔、視訊等)無法處理。

是以,在實際爬蟲開發中,需要根據具體情況選擇合适的資料解析方法。

一丶正規表達式

1.正則原理概述

在爬蟲中,資料解析是非常重要的一環,因為資料解析子產品的好壞将直接決定了爬蟲的效率和準确度。正規表達式是資料解析中常用的一種技術,下面就來簡要介紹一下正規表達式的原理。

正規表達式(Regular Expression)即為正則或稱規則表達式,是一套用于描述、比對和處理文本的符号規則。在爬蟲中,正規表達式常被用于從HTML文本中提取出我們需要的資料。正規表達式的文法非常強大,包括字元集、元字元、量詞、分組等許多特性,能夠滿足各種複雜的比對需求。下面簡要介紹一些正規表達式的文法:

字元集

字元集(Character Classes,也稱字元組)一般用方括号表示,用于表示一組可選字元。比如,[abc]表示可選任意一個字母a、b或c。其中還有一些常用的簡寫形式,如\d表示任意一個數字(等價于[0-9]),\w表示任意一個字母、數字或下劃線(等價于[a-zA-Z0-9_]),\s表示任意一個空白字元(包括空格、制表符、回車符等)。

元字元

元字元(Metacharacters)是正規表達式中具有特殊含義的字元,如 \、^、$、*、+、?、.、|、()、{m,n} 等等。這些字元在正規表達式中并非表示字面意義,而是具有某種特殊的含義。

量詞

量詞用于指定字元或子表達式出現的次數,常用的量詞包括:

  • *:表示任意個字元(包括零個字元)
  • +:表示至少一個字元
  • ?:表示零個或一個字元
  • {m}:表示恰好出現 m 次
  • {m,n}:表示至少出現 m 次,最多出現 n 次

分組

分組用小括号括起來,用于将多個部分組合在一起。分組還允許應用量詞,即在一個組内表示一定數量的字元。

當然,正規表達式也存在一些限制。由于正規表達式本身較為複雜,容易出現邏輯上的錯誤,在使用時需要注意。此外,在處理海量資料時,正規表達式的效率可能會成為影響程式性能的瓶頸。

綜上所述,正規表達式是資料解析中非常常用的一種技術,掌握正規表達式的文法規則,能夠更友善地從HTML文本中提取出所需的資料。

2.分組和通用比對

正規表達式是一種用于比對文本的工具,它可以用來解析HTML、XML等文本格式的資料。在正規表達式中,分組和通用比對是兩個常用的概念。

1.分組

分組是指将正規表達式中的一部分用括号括起來,形成一個子表達式。分組可以用來限定比對範圍、提取比對結果等。

例如,正規表達式?(.?)中,用括号括起來的部分就是分組,第一個分組(.?)用來比對連結位址,第二個分組(.*?)用來比對連結文本。

2.通用比對

通用比對是指用.來比對任意字元的正規表達式。通用比對可以用來比對一些不确定的字元,例如空格、換行符等。

例如,正規表達式?.*?中,用.來比對連結位址和連結文本中間的任意字元,這樣就可以比對包含任意字元的連結了。

需要注意的是,通用比對可能會比對到一些不需要的字元,是以在使用時需要謹慎。

3.貪婪和非貪婪模式**

在爬蟲工程師的采集工作中,資料解析是非常重要的一環節。正規表達式是一種強大的工具,可以用于從網頁中提取有用的資訊。在正規表達式中,貪婪和非貪婪模式是一個關鍵的概念,因為它們直接影響到正規表達式的比對結果。

正規表達式中的貪婪模式指的是比對盡可能多的字元,而非貪婪模式則是比對盡可能少的字元。預設情況下,正規表達式是貪婪的,這意味着它會嘗試比對盡可能多的字元。例如,考慮以下正規表達式:

.*hello.*           

該正規表達式将比對任何字元串,隻要它包含子字元串“hello”。但是,如果我們使用該正規表達式對以下字元串進行比對:

"hello world! hello goup!"           

結果将是整個字元串,而不僅僅是第一個“hello”字元串。這是因為正規表達式會貪婪地比對盡可能多的字元,直到找到最後一個“hello”。

要使用非貪婪模式,可以在正規表達式中使用“?”符号。例如,如果我們想要上面的正規表達式隻比對第一個“hello”,可以這樣寫:

.*?hello.*           

這個正規表達式将會比對到第一個“hello”,因為它使用了非貪婪模式,盡可能少地比對字元,直到找到第一個“hello”。

總的來說,在資料解析和爬蟲采集過程中,要根據需要選擇合适的正規表達式模式。如果需要比對盡可能多的字元,則應該使用貪婪模式;如果需要比對盡可能少的字元,則應該使用非貪婪模式。很多時候,貪婪模式會導緻意外的比對結果,是以需要特别小心。

4.findall/match/search方法

在Python中,re子產品提供了三種方法來比對正規表達式:findall、match和search。

findall方法

findall方法可以在字元串中查找所有比對正規表達式的子串,并傳回一個清單。例如:

import re

text = 'Hello, my name is John. My email is [email protected].'
emails = re.findall(r'\b\w+@\w+\.\w+\b', text)
print(emails)           

輸出結果為:

['[email protected]']           

match方法

match方法隻能在字元串的開頭比對正規表達式,如果比對成功,則傳回一個比對對象,否則傳回None。例如:

import re

text = 'Hello, my name is John. My email is [email protected].'
match = re.match(r'\b\w+@\w+\.\w+\b', text)
if match:
    print(match.group())
else:
    print('No match')           

輸出結果為:

No match           

因為正規表達式\b\w+@\w+.\w+\b隻能比對單詞邊界處的郵箱位址,而字元串的開頭不是單詞邊界。

search方法

search方法可以在字元串中查找第一個比對正規表達式的子串,并傳回一個比對對象,否則傳回None。例如:

import re

text = 'Hello, my name is John. My email is [email protected].'
match = re.search(r'\b\w+@\w+\.\w+\b', text)
if match:
    print(match.group())
else:
    print('No match')           

輸出結果為:

[email protected]           

因為search方法會在整個字元串中查找比對正規表達式的子串。

二丶xpath

XPath是一種用于在XML文檔中定位元素和屬性的語言,也可以用于HTML文檔的解析。在PC端爬蟲工程師采集資料時,XPath可以幫助我們快速準确地定位到需要的資料。

XPath的文法比較簡單,主要由路徑表達式和基本表達式組成。路徑表達式用于定位元素,基本表達式用于定位屬性或文本。

以下是一些常用的XPath表達式:

定位元素

  • //tagname:選取所有名稱為tagname的元素
  • /tagname:選取根元素下的所有名稱為tagname的元素
  • /path/tagname:選取路徑為path下的所有名稱為tagname的元素

定位屬性

  • //@attribute:選取所有名稱為attribute的屬性
  • /path/@attribute:選取路徑為path下的所有名稱為attribute的屬性

定位文本

  • //tagname/text():選取所有名稱為tagname的元素的文本内容
  • /path/tagname/text():選取路徑為path下的所有名稱為tagname的元素的文本内容

XPath的使用需要借助解析庫,比如Python中的lxml庫。使用lxml庫可以通過xpath()方法來解析HTML或XML文檔,擷取需要的資料。

例如,以下代碼可以擷取百度首頁的搜尋框的名稱:

import requests
from lxml import etree

url = 'https://www.baidu.com/'
response = requests.get(url)
html = etree.HTML(response.text)
input_name = html.xpath('//input[@id="kw"]/@name')[0]
print(input_name)           

輸出結果為:

'wd'           

這裡使用了xpath表達式//input[@id="kw"]/@name來定位搜尋框元素的名稱屬性。

1.dom節點

在使用XPath進行資料解析時,需要了解DOM節點的概念。

DOM(Document Object Model)是一種用于表示和操作HTML或XML文檔的标準對象模型。在DOM中,文檔被表示為一個樹形結構,每個節點都是一個對象,包含了文檔中的元素、屬性、文本等資訊。

在XPath中,每個節點都有一個節點類型,常見的節點類型包括:

  • 元素節點(Element Node):表示XML或HTML文檔中的元素,如、等。
  • 屬性節點(Attribute Node):表示XML或HTML文檔中的屬性,如class、id等。
  • 文本節點(Text Node):表示XML或HTML文檔中的文本内容,如hello world中的hello world。

在XPath中,可以使用不同的文法來選擇DOM節點,常見的文法包括:

  • 路徑表達式(Path Expression):使用路徑表達式可以選擇文檔中的某個節點或一組節點。例如,選擇所有的元素可以使用路徑表達式//div。
  • 軸(Axis):軸是一種用于選擇節點的方法,可以選擇與目前節點有特定關系的節點。例如,選擇目前節點的所有子節點可以使用軸child::。
  • 謂語(Predicate):謂語是一種用于過濾節點的方法,可以根據節點的屬性或位置等資訊來選擇節點。例如,選擇第一個元素可以使用路徑表達式(//div)[1]。

掌握DOM節點的概念和XPath的文法,可以更加靈活地進行資料解析。

2.xpath文法學習

XPath(XML Path Language)是一種用于在XML文檔中定位元素和屬性的語言。XPath使用路徑表達式來選擇和操作XML文檔中的節點。

以下是XPath文法中的一些基本概念:

  • 節點:XML文檔中的元素、屬性等都是節點。
  • 路徑表達式:一種用來表示選擇某個節點或一組節點的字元串。
  • 路徑:路徑指定從文檔根節點到所選節點的方式,可以是絕對路徑或相對路徑。
  • 謂語:謂語用于篩選節點,可以是一個表達式或條件。

XPath文法示例:

選擇節點:

//book  //表示從任意節點開始檢索
/book  /表示從根節點開始檢索
book   表示選擇名為"book"的節點           

選擇屬性:

//@class  選擇所有名為"class"的屬性           

謂語:

//student[age>20]  選擇名為"student"且"age"大于20的節點
層級://bookstore/book/title 選擇所有名為"bookstore"的節點下的名為"book"的節點下的名為"title"的節點           

XPath的文法非常直覺,容易了解和記憶。在使用XPath文法進行資料解析時,可以使用Python中的lxml庫來實作,使用方法也非常簡單。使用lxml庫和XPath文法,可以将HTML或XML文檔中的資料提取出來并儲存為結構化資料,用于後續的分析和處理。

3.xpath定位文章資料

在使用XPath定位文章資料時,需要先用浏覽器開發者工具分析文章頁面的HTML結構,找出要提取的資料所在的節點,然後使用XPath文法來篩選這些節點。

以下是一個示例,假設我們要從一個部落格的文章頁面中提取文章标題、作者、釋出時間和正文:

<html>
  <head>
    <title>Blog Title</title>
  </head>
  <body>
    <div class="article">
      <h1 class="title">Article Title</h1>
      <p class="author">Author Name</p>
      <p class="publish-time">2023-06-09 20:08:20</p>
      <div class="content">
        <p>Article Content Paragraph 1</p>
        <p>Article Content Paragraph 2</p>
        <p>Article Content Paragraph 3</p>
      </div>
    </div>
  </body>
</html>           

使用XPath文法,可以定位到需要提取的節點:

//h1[@class='title']  # 定位到文章标題節點
//p[@class='author']  # 定位到作者節點
//p[@class='publish-time']  # 定位到釋出時間節點
//div[@class='content']/p  # 定位到正文每一段的節點           

然後使用Python中的lxml庫解析HTML,提取出這些節點的文本内容:

from lxml import etree

# 解析HTML
html = etree.parse('article.html', etree.HTMLParser())

# 提取節點文本
title = html.xpath('//h1[@class="title"]/text()')[0]
author = html.xpath('//p[@class="author"]/text()')[0]
publish_time = html.xpath('//p[@class="publish-time"]/text()')[0]
content = '\n'.join(html.xpath('//div[@class="content"]/p/text()'))           

這樣就可以将文章的資訊提取出來,其中title、author和publish_time為字元串,content為字元串清單,每個元素為正文中的一段。後面可以根據需要将這些資料儲存到檔案或資料庫中,或者進行其他的資料處理。

三丶Beautiful

在進行網頁資料解析時,我們需要使用一些工具來幫助我們快速地定位和提取所需的資料。其中,Beautiful Soup是一個非常常用的Python庫,它可以幫助我們解析HTML和XML文檔,并提供了一些友善的方法來定位和提取資料。

安裝Beautiful Soup

在使用Beautiful Soup之前,我們需要先安裝它。可以使用pip指令來安裝:

pip install beautifulsoup4           

使用Beautiful Soup

安裝完成後,我們就可以開始使用Beautiful Soup了。下面是一個簡單的例子,示範了如何使用Beautiful Soup來解析HTML文檔:

from bs4 import BeautifulSoup

html_doc = """
<html>
<head>
    <title>這是一個示例頁面</title>
</head>
<body>
    <h1>歡迎來到我的網站</h1>
    <p class="content">這是一個示例頁面,用于示範Beautiful Soup的使用方法。</p>
    <ul>
        <li><a href="http://www.example.com">連結1</a></li>
        <li><a href="http://www.example.com">連結2</a></li>
        <li><a href="http://www.example.com">連結3</a></li>
    </ul>
</body>
</html>
"""

soup = BeautifulSoup(html_doc, 'html.parser')
print(soup.prettify())           

在這個例子中,我們首先定義了一個HTML文檔的字元串,然後使用Beautiful Soup的構造函數來建立一個BeautifulSoup對象。構造函數的第二個參數指定了解析器的類型,這裡我們使用了Python内置的html.parser解析器。

接下來,我們調用了BeautifulSoup對象的prettify()方法,将解析後的HTML文檔格式化輸出。這個方法可以将HTML文檔按照标準的縮進格式輸出,友善我們檢視和調試。

定位元素

在使用Beautiful Soup解析HTML文檔時,我們通常需要定位文檔中的某些元素,然後提取它們的内容或屬性。Beautiful Soup提供了一些友善的方法來定位元素,下面是一些常用的方法:

  • find()方法:查找文檔中第一個符合條件的元素。
  • find_all()方法:查找文檔中所有符合條件的元素,并傳回一個清單。
  • select()方法:使用CSS選擇器文法查找文檔中符合條件的元素。

下面是一個例子,示範了如何使用這些方法來定位元素:

from bs4 import BeautifulSoup

html_doc = """
<html>
<head>
    <title>這是一個示例頁面</title>
</head>
<body>
    <h1>歡迎來到我的網站</h1>
    <p class="content">這是一個示例頁面,用于示範Beautiful Soup的使用方法。</p>
    <ul>
        <li><a href="http://www.example.com">連結1</a></li>
        <li><a href="http://www.example.com">連結2</a></li>
        <li><a href="http://www.example.com">連結3</a></li>
    </ul>
</body>
</html>
"""

soup = BeautifulSoup(html_doc, 'html.parser')

# 使用find()方法查找第一個符合條件的元素
title = soup.find('title')
print(title)

# 使用find_all()方法查找所有符合條件的元素
links = soup.find_all('a')
for link in links:
    print(link)

# 使用select()方法使用CSS選擇器文法查找元素
content = soup.select('.content')
print(content)           

在這個例子中,我們首先使用find()方法查找了文檔中的第一個title元素,并将其列印出來。接下來,我們使用find_all()方法查找了所有的a元素,并使用for循環将它們列印出來。最後,我們使用select()方法使用CSS選擇器文法查找了所有class為content的元素,并将其列印出來。

提取内容和屬性

在定位到元素後,我們通常需要提取它們的内容或屬性。Beautiful Soup提供了一些友善的方法來實作這個功能,下面是一些常用的方法:

  • text屬性:擷取元素的文本内容。
  • string屬性:擷取元素的文本内容,與text屬性類似,但是對于一些特殊的标簽(如script、style等)會傳回None。
  • get()方法:擷取元素的指定屬性值。

下面是一個例子,示範了如何使用這些方法來提取内容和屬性:

from bs4 import BeautifulSoup

html_doc = """
<html>
<head>
    <title>這是一個示例頁面</title>
</head>
<body>
    <h1>歡迎來到我的網站</h1>
    <p class="content">這是一個示例頁面,用于示範Beautiful Soup的使用方法。</p>
    <ul>
        <li><a href="http://www.example.com">連結1</a></li>
        <li><a href="http://www.example.com">連結2</a></li>
        <li><a href="http://www.example.com">連結3</a></li>
    </ul>
</body>
</html>
"""

soup = BeautifulSoup(html_doc, 'html.parser')

# 擷取元素的文本内容
title_text = soup.title.text
print(title_text)

# 擷取元素的指定屬性值
link = soup.find('a')
link_href = link.get('href')
print(link_href)           

在這個例子中,我們首先使用text屬性擷取了title元素的文本内容,并将其列印出來。接下來,我們使用find()方法查找了第一個a元素,并使用get()方法擷取了它的href屬性值,并将其列印出來。

總結

Beautiful Soup是一個非常常用的Python庫,它可以幫助我們解析HTML和XML文檔,并提供了一些友善的方法來定位和提取資料。在使用Beautiful Soup時,我們通常需要使用find()、find_all()和select()等方法來定位元素,然後使用text、string和get()等方法來提取内容和屬性。

2.基于bs4的環境搭建

在使用BeautifulSoup之前,需要先安裝bs4庫。可以使用pip指令安裝:

pip install bs4           

環境搭建完成後,可以進行以下操作。

初始化BeautifulSoup對象

BeautifulSoup初始化時需要兩個參數,第一個參數是HTML或XML文檔的字元串,第二個參數是指定使用哪種解析器進行解析。常用的解析器包括html.parser、lxml和html5lib,其中lxml解析器解析速度較快,而html5lib解析器則能夠處理一些文法非常松散的HTML文檔。

以下是根據HTML文檔初始化BeautifulSoup對象的代碼:

from bs4 import BeautifulSoup

html_doc = '''<html>
<head>
    <title>網頁标題</title>
</head>
<body>
    <h1 class="title">網頁正文</h1>
    <div class="content">
        <p>第一段内容</p>
        <p>第二段内容</p>
        <p>第三段内容</p>
        <ul>
            <li><a href="http://www.example.com">連結一</a></li>
            <li><a href="http://www.example.com">連結二</a></li>
            <li><a href="http://www.example.com">連結三</a></li>
        </ul>
    </div>
</body>
</html>'''

soup = BeautifulSoup(html_doc, 'html.parser')  # 使用html.parser解析器初始化BeautifulSoup對象           

查找元素

使用BeautifulSoup中的find()和find_all()方法可以查找符合條件的元素。find()方法傳回第一個符合條件的元素,find_all()方法傳回符合條件的所有元素。

以下是根據标簽和屬性查找元素的代碼:

# 查找所有p元素
ps = soup.find_all('p')
for p in ps:
    print(p.get_text())

# 查找所有class屬性值為content的元素
contents = soup.find_all(class_='content')
for content in contents:
    print(content.get_text())           

提取元素屬性

使用元素對象的attrs屬性可以擷取所有屬性值,使用get()方法可以擷取某個特定屬性值。

以下是根據屬性提取元素的代碼:

# 擷取所有a标簽的href屬性
a_s = soup.find_all('a')
for a in a_s:
    print(a['href'])

# 擷取第一個a标簽的href屬性
a = soup.find('a')
print(a.get('href'))           

使用CSS選擇器

使用BeautifulSoup的select()方法可以通過CSS選擇器查找元素。

以下是使用CSS選擇器的代碼:

# 查找所有class屬性值為content的div元素下的所有p元素
ps = soup.select('.content p')
for p in ps:
    print(p.get_text())

# 查找第一個ul元素下的所有li元素
lis = soup.select('ul li')
for li in lis:
    print(li.get_text())           

BeautifulSoup提供了許多方法可以友善地操作HTML和XML文檔,具體使用可以參照官方文檔進行。

3.bs4節點選擇器

在使用BeautifulSoup解析HTML代碼時,通過節點選擇器可以選擇HTML文檔中的指定部分,常用的節點選擇器包括标簽選擇器、類選擇器、id選擇器、屬性選擇器等。

标簽選擇器

标簽選擇器是最常用的選擇器,它根據HTML标簽名稱來選擇HTML文檔中的元素。可以使用find()或find_all()方法來實作标簽選擇器。

# 選擇第一個p标簽
soup.find('p')

# 選擇所有p标簽
soup.find_all('p')           

類選擇器

類選擇器是通過元素的class屬性進行選擇,可以使用CSS選擇器文法來選擇單個或多個類。

# 選擇class為"foo"的元素
soup.select('.foo')

# 選擇同時具有class為"foo"和"bar"的元素
soup.select('.foo.bar')           

id選擇器

id選擇器是根據id屬性進行選擇,可以使用CSS選擇器文法選擇具有指定id的元素。可以使用find()方法來實作id選擇器。

# 選擇id為"myid"的元素
soup.find(id='myid')           

屬性選擇器

屬性選擇器是根據元素的屬性值來選擇元素。可以使用find_all()方法和屬性名選擇單個或多個元素。

# 選擇所有具有href屬性的a标簽
soup.find_all('a', href=True)           

子選擇器

子選擇器是通過選擇器名稱的空格分隔符來實作選擇父元素下的子元素。

# 選擇div元素下的所有p元素
soup.select('div p')           

後代選擇器

後代選擇器使用選擇器名稱的大于号>分隔符來實作選擇某個父元素下的直接子元素。

# 選擇div元素下的直接子元素p元素
soup.select('div > p')           

兄弟選擇器

兄弟選擇器是指選擇與指定元素處于同一層級但不一定是相鄰的元素。可以使用選擇器名稱的+符号選擇下一個兄弟元素,使用選擇器名稱的~符号選擇所有兄弟元素。

# 選擇id為"foo"元素的下一個兄弟元素
soup.select('#foo + p')

# 選擇id為"foo"元素的所有兄弟元素
soup.select('#foo ~ p')           

以上就是使用BeautifulSoup的節點選擇器的常用方法,基于選擇器的使用,可以解析和提取HTML文檔中的各種元素和屬性資訊。

4.bs4屬性選擇器

在Beautiful Soup中,我們可以使用屬性選擇器來選擇具有特定屬性的标簽。屬性選擇器使用方括号[]來指定屬性名稱和屬性值。

以下是一些常用的屬性選擇器:

選擇具有特定屬性的标簽

soup.select('tag[attr]')           

例如,選擇所有具有class屬性的div标簽:

soup.select('div[class]')           

選擇具有特定屬性和屬性值的标簽

soup.select('tag[attr=value]')           

例如,選擇所有class屬性為"example"的div标簽:

soup.select('div[class=example]')           

選擇具有特定屬性但不限制屬性值的标簽

soup.select('tag[attr*]')           

例如,選擇所有具有id屬性的标簽:

soup.select('[id*]')           

選擇具有特定屬性值的标簽,但不限制屬性名稱

soup.select('[*=value]')           

例如,選擇所有屬性值包含"example"的标簽:

soup.select('[*=example]')           

選擇具有多個屬性的标簽

soup.select('tag[attr1][attr2]')           

例如,選擇所有同時具有class屬性為"example"和id屬性為"test"的div标簽:

soup.select('div[class=example][id=test]')           

5.bs4層級選擇器

BeautifulSoup庫提供了一些層級選擇器,可以用于選擇HTML文檔中的指定層級元素。層級選擇器可以嵌套使用,以實作更精細的元素選擇。

以下是bs4層級選擇器的幾個常見方法:

descendants選擇器

該選擇器用于選擇目前元素的所有後代元素,包括子元素、子元素的子元素、子元素的子元素的子元素等。使用descendants方法進行查找,傳回所有後代元素的生成器對象。

# 選擇id為"content"的div元素的所有後代元素
for elem in soup.find('div', id='content').descendants:
    print(elem)           

children選擇器

該選擇器用于選擇目前元素的所有子元素,不包括子元素的子元素。使用children方法進行查找,傳回目前元素的所有子元素的生成器對象。

# 選擇id為"content"的div元素的所有子元素
for elem in soup.find('div', id='content').children:
    print(elem)           

parent選擇器

該選擇器用于選擇目前元素的父元素,使用parent方法進行查找,傳回目前元素的父元素。

# 選擇id為"myid"的元素的父元素
parent = soup.find(id='myid').parent           

parents選擇器

該選擇器用于選擇目前元素的所有祖先元素,傳回一個生成器對象。與descendants方法不同,該方法隻傳回直接祖先元素,不包括更遠的祖先元素。

# 選擇id為"myid"的元素的所有祖先元素
for ancestor in soup.find(id='myid').parents:
    print(ancestor)           

next_sibling和previous_sibling選擇器

next_sibling選擇器用于選擇目前元素的下一個兄弟元素,previous_sibling選擇器用于選擇目前元素的上一個兄弟元素。

# 選擇id為"myid"的元素的下一個兄弟元素
next_sibling = soup.find(id='myid').next_sibling           

以上就是bs4層級選擇器的常見方法,這些方法可以很好地幫助我們選擇HTML文檔中的特定元素來進行後續的資料提取和處理。

3.資料入庫

前言

資料入庫是指将采集好的資料存儲到資料庫中以便後續處理和分析。作為一名PC端爬蟲工程師,掌握資料入庫技能是必不可少的。在進行資料采集的同時,将資料實時地存儲到資料庫中,可以讓資料得到更好地管理和利用,提高效率和效益。

一般而言,進行資料入庫有以下幾個步驟:

  • 資料庫的建立和配置:選擇一個合适的資料庫,根據實際需要建立資料庫表和配置資料庫連接配接等參數。
  • 資料庫連接配接:建立資料庫與Python的連接配接。有關Python連接配接資料庫的方法有很多種,比如通過Python自帶的SQLite資料庫子產品、通過MySQL Connector等第三方庫進行連接配接。
  • 資料準備和清洗:在進行資料入庫之前,需要進行針對性的資料準備和清洗工作。比如,對采集到的資料進行初步處理,處理掉無意義的資料,将有用的資料組織好。
  • 資料的插入和更新:通過Python提供的資料庫操作工具(如SQLAlchemy)或sql語句來進行資料的插入和更新操作。
  • 資料庫的維護:包括對資料庫表的清理、優化和備份等操作,以確定資料庫的穩定運作。

需要注意的是,資料庫入庫不僅涉及到資料庫本身的知識,還需要對Python程式設計語言有一定的掌握。是以,PC端爬蟲工程師在進行資料入庫之前,需要先掌握Python的基礎文法,熟練掌握Python的相關技巧,才能順利地進行資料采集和入庫工作。

總而言之,資料入庫是PC端爬蟲工程師不可或缺的一項技能。隻有掌握好資料入庫技能,才能為企業或個人實作更好地資料分析和應用,提高資料價值。

從零開始學python(十二)如何成為一名優秀的爬蟲工程師

一丶MySQL

MySQL是一種常用的關系型資料庫管理系統,廣泛應用于各種應用場景。在進行資料采集和入庫工作時,掌握MySQL資料庫的使用是極為重要的。

1.MySQL表結構設計

MySQL表結構設計是進行資料入庫時需要考慮的一個重要問題。一個好的表結構設計可以保證資料的存儲和管理更加高效和便捷。以下是幾個關鍵點,供PC端爬蟲工程師在進行MySQL表結構設計時參考:

  • 字段設定:在表結構設計中,需要設定字段和對應的資料類型。字段的設定需考慮資料的類型、長度、是否允許為空、是否唯一、是否自增等因素。在設計字段時需遵循最小化原則,避免不必要的字段,以減輕資料庫處理壓力。
  • 主鍵、唯一鍵、索引等設定:通過索引可以提高查詢的效率,是以在資料入庫時應該考慮添加索引。一般而言,需要給表中的字段設定主鍵、唯一鍵和普通索引等,以優化資料的查詢性能。
  • 表的級聯關系:在設計表結構時,需要考慮多表之間的關系。比如,是采用多個獨立的表,還是将其合并為一個複雜的表。還需考慮多表之間的級聯關系,以確定資料的一緻性。
  • 設定資料表的字元集和排序規則:在MySQL表的結構設計中,還需考慮字元集和排序規則的設定。要根據實際情況,選擇合适的字元集和排序規則,以避免資料存儲時出現亂碼或者排序問題。

2.MySQL資料寫入規範

MySQL資料寫入規範是進行資料入庫時需要考慮的一個重要問題。一個良好的資料寫入規範可以保證資料的準确性和一緻性,確定資料在資料庫中的正确存儲。以下是PC端爬蟲工程師需要遵循的MySQL資料寫入規範:

  • 字段值格式與表結構比對:在進行資料寫入時,需要確定字段值的格式與表結構比對。即使資料庫允許資料随意寫入,也應該遵循表結構設計的原則,将資料寫入到正确的字段中。
  • 資料的完整性:在進行資料寫入時,需要確定資料的完整性。應盡量避免資料缺失、重複或者錯誤等問題,以免對後續分析和應用造成影響。
  • 資料的規範化:對于涉及字元串、日期等資料類型的字段,需要考慮到資料的規範化。比如,對于日期資料,應統一使用一種日期格式,并避免使用預設格式等導緻的問題。
  • 事務管理:在進行資料寫入時,應盡量使用事務來確定資料的一緻性。比如,在寫入多條記錄時,可以将它們一起寫入到資料庫中,并在最後再統一送出,以確定資料在寫入的過程中保持一緻性。
  • 避免超限資料的寫入:在進行資料寫入時,應嚴格避免超限資料的寫入,例如資料長度超出字段長度等問題。如果資料超限,會導緻資料丢失或者資料庫撐爆等問題。

3.MySQL動态傳參

MySQL動态傳參是進行資料入庫時經常用到的一種技巧。通過動态傳參,可以有效地提高MySQL資料庫寫入的效率,減少程式代碼的備援,優化資料入庫過程。以下是幾種常用的MySQL動态傳參方式:

使用Python的字元串格式化方法進行動态傳參:可以使用Python的字元串的format方法進行MySQL參數的傳遞。在進行資料寫入操作時,可以将MySQL語句和Python字典或元組進行結合,實作動态傳參的效果。例如:

import MySQLdb

# 定義資料表名
table_name = "student"

# 定義學生資訊
student_info = {
    "name": "Tom",
    "age": 18,
    "grade": "A"
}

# 動态傳參
sql = "INSERT INTO {table_name} (name, age, grade) VALUES ('{name}', {age}, '{grade}')".format(
    table_name=table_name,
    name=student_info['name'],
    age=student_info['age'],
    grade=student_info['grade']
)

# 連接配接資料庫
conn = MySQLdb.connect('localhost', 'username', 'password', 'database_name')
# 擷取遊标對象
cursor = conn.cursor()
# 執行操作
cursor.execute(sql)
# 送出事務
conn.commit()
# 關閉遊标和連接配接
cursor.close()
conn.close()           

使用MySQLdb子產品的execute方法進行動态傳參:使用MySQLdb的execute方法進行動态傳參,隻需要在SQL語句中使用占位符%s,然後在執行execute方法時傳遞參數清單即可。例如:

import MySQLdb

# 定義資料表名
table_name = "student"

# 定義學生資訊
student_info = {
    "name": "Tom",
    "age": 18,
    "grade": "A"
}

# 動态傳參
sql = "INSERT INTO {table_name} (name, age, grade) VALUES (%s, %s, %s)".format(
    table_name=table_name
)

# 連接配接資料庫
conn = MySQLdb.connect('localhost', 'username', 'password', 'database_name')
# 擷取遊标對象
cursor = conn.cursor()
# 執行操作
cursor.execute(sql, (student_info['name'], student_info['age'], student_info['grade']))
# 送出事務
conn.commit()
# 關閉遊标和連接配接
cursor.close()
conn.close()           

總之,MySQL動态傳參是進行資料入庫時經常使用的一種技巧。PC端爬蟲工程師掌握MySQL動态傳參的使用方法,可以對SQL語句進行動态的參數傳遞,進而提高資料庫寫入的效率、減少代碼備援。在進行資料入庫時,建議使用MySQL動态傳參技巧,以提高資料的寫入效率和準确性。

4.MySQL對接爬蟲實戰

在進行爬蟲資料采集和入庫時,MySQL是一個常用的關系型資料庫管理系統,其穩定性和可靠性被廣泛認可。以下是PC端爬蟲工程師可以按照的步驟,将爬蟲采集資料寫入到MySQL資料庫中:

  • 建立MySQL資料庫表結構:在MySQL資料庫中建立一個資料表,該表的表結構應根據資料的類型和存儲需求進行設計。在表結構設計時需要考慮字段設定、主鍵、唯一鍵、索引等因素。
  • 使用Python中的爬蟲架構進行資料采集:使用Python中的Scrapy或者BeautifulSoup等常用的PC端爬蟲架構進行資料采集,将采集到的資料存儲在Python的變量中。
  • 連接配接MySQL資料庫:使用Python的MySQLdb或pymysql等第三方庫連接配接MySQL資料庫,并進行相應的參數配置。
  • 實作資料寫入操作:使用Python的cursor對象,通過sql語句将資料插入到MySQL資料庫中。在插入資料時,需要遵循MySQL資料庫的資料寫入規範,保證資料的完整性、一緻性和安全性。如果需要動态傳參,在插入資料時還需要用到字元串格式化方法或者MySQLdb的execute方法進行動态傳參。
  • 關閉資料庫連接配接:當完成資料入庫操作後,應及時關閉資料庫連接配接,以釋放資源。

下面是一個将采集到的資料寫入MySQL資料庫的示例代碼:

import MySQLdb

# 連接配接MySQL資料庫
conn = MySQLdb.connect('localhost', 'username', 'password', 'database_name')

# 擷取遊标對象
cursor = conn.cursor()

# 采集到的資料
book = {'name': 'Python入門精通', 'author': '張三', 'price': 28}

# 資料庫寫入操作
sql = "INSERT INTO books (name, author, price) VALUES ('%s', '%s', %f)" % (book['name'], book['author'], book['price'])
try:
    # 執行SQL語句
    cursor.execute(sql)
    # 送出事務
    conn.commit()
except Exception as e:
    # 發生異常時復原
    print(str(e))
    conn.rollback()

# 關閉遊标和連接配接
cursor.close()
conn.close()           

将爬蟲采集的資料寫入MySQL資料庫是PC端爬蟲工程師需要掌握的重要技能之一。需要合理設計資料表結構,使用Python的爬蟲架構進行資料采集,正确連接配接MySQL資料庫,遵循MySQL的資料寫入規範進行資料寫入操作,并嚴格保障資料的完整性和一緻性。

二丶MongoDB

除了關系型資料庫MySQL,另一種非常流行的資料庫是NoSQL資料庫MongoDB。相比于MySQL,MongoDB具備更好的可擴充性和更友善的資料處理方式,是現代Web應用程式的熱門選擇。以下是将爬蟲采集資料寫入MongoDB資料庫的步驟:

  • 安裝MongoDB資料庫:在開始使用MongoDB資料庫之前,需要安裝MongoDB以及相應的Python驅動程式pymongo。MongoDB官網提供了各種安裝方式和文檔。
  • 連接配接MongoDB資料庫:使用pymongo庫連接配接MongoDB資料庫,并進行相應的參數配置。MongoDB需要指定資料庫所在伺服器位址、端口号、資料庫名稱等連接配接資訊。
  • 建立MongoDB資料庫和集合:MongoDB是面向文檔的資料庫,不需要像MySQL一樣設計表結構,而是直接存儲JSON格式的文檔。可以首先建立MongoDB資料庫和集合,然後在代碼中直接插入文檔。使用pymongo庫提供的MongoClient對象可以連接配接MongoDB資料庫,并使用相應的方法建立資料庫和集合等。
  • 實作資料寫入操作:使用pymongo庫提供的insert_one或insert_many等方法将Python變量中的資料插入到MongoDB中。在插入資料時,需要遵循MongoDB的資料寫入規範,保證資料的完整性、一緻性和安全性。如果需要動态傳參,在插入資料時還需要用到Python格式化字元串或bson子產品的tobson方法。
  • 關閉資料庫連接配接:當完成資料入庫操作後,應及時關閉資料庫連接配接,以釋放資源。

下面是一個将采集到的資料寫入MongoDB資料庫的示例代碼:

import pymongo
import json

# 連接配接MongoDB資料庫
client = pymongo.MongoClient(host='localhost', port=27017)

# 建立MongoDB資料庫和集合
db = client['bookstore']
collection = db['books']

# 采集到的資料
book = {'name': 'Python入門精通', 'author': '張三', 'price': 28}

# 資料庫寫入操作
try:
    # 将Python字典轉換為MongoDB的文檔格式
    doc = json.loads(json.dumps(book))
    # 插入文檔到MongoDB
    collection.insert_one(doc)
except Exception as e:
    print(str(e))

# 關閉MongoDB連接配接
client.close()           

将爬蟲采集的資料寫入MongoDB資料庫是PC端爬蟲工程師需要掌握的另一個重要技能。需要首先安裝MongoDB資料庫和Python驅動程式pymongo,然後使用pymongo庫連接配接MongoDB資料庫,建立資料庫和集合,使用insert_one和insert_many等方法将資料插入到MongoDB中。同時也需要遵循MongoDB的資料寫入規範,保障資料的完整性和一緻性。

1.MongoDB資料寫入規範

MongoDB是一種非關系型資料庫,相對于傳統關系型資料庫MySQL,它有許多的特性和優勢,但是在使用時需要遵守一定的資料寫入規範,以保證資料的安全性和一緻性。下面是在将資料寫入MongoDB時需要遵守的規範:

  • 字段命名規範:MongoDB支援使用Unicode字元集中的所有字元作為字段名稱,但是不推薦使用除字母數字和下劃線以外的特殊字元,且建議使用小寫字母。字段名稱不能為空字元串,并且不能以$開頭。
  • 資料格式規範:在将資料寫入MongoDB中時,需要保證文檔中每個字段的資料類型和資料格式的一緻性。如果想要将Python中的資料寫入MongoDB,可以先将Python中的資料格式化為JSON字元串或字典,然後再将其轉換為MongoDB文檔格式。
  • 文檔唯一性規範:MongoDB中的每個文檔都應該具有唯一的_id字段。如果在寫入文檔時沒有指定_id字段,則MongoDB會為每個文檔自動生成一個ObjectId類型的_id字段。
  • 資料寫入确認規範:當使用MongoDB寫入資料時,應該使用寫入确認來確定資料已經成功寫入資料庫。MongoDB提供了四種寫入确認級别,分别為:未确認寫入、确認主節點寫入、确認大多數節點寫入和确認所有節點寫入。
  • 資料更新規範:在更新MongoDB中的文檔時,可以使用update方法進行更新。使用update方法時,需要指定更新的文檔、更新的方式和更新的條件。如果不指定更新條件,則預設會更新所有符合條件的文檔。更新操作還可以将某個字段的值進行遞增或遞減操作。
  • 資料删除規範:在MongoDB中删除文檔時,可以使用remove方法進行删除。使用remove方法時,需要指定删除的文檔和删除的條件。如果不指定條件,則預設會删除所有文檔。

在将資料寫入MongoDB中時,需要遵守一定的規範,以保證資料的安全性和一緻性。需要注意字段命名規範、資料格式規範、文檔唯一性規範、資料寫入确認規範、資料更新規範和資料删除規範。

2.MongoDB資料異常處理

在進行資料入庫到MongoDB的過程中,可能會遇到一些異常情況,例如寫入資料失敗、查詢資料出錯等等。為了保證資料的完整性和正确性,需要進行一些異常處理。

以下是在使用MongoDB進行資料入庫時,可能會遇到的異常情況及相應的處理方法:

  • 寫入資料失敗:在将資料寫入MongoDB的過程中,可能會由于網絡問題、資料庫連接配接失敗或者其他原因導緻寫入失敗。此時,需要進行重試操作,并且可以使用MongoDB提供的異常處理機制來捕獲異常,并進行相應的處理。
  • 查詢資料出錯:在查詢MongoDB中的文檔時,可能會由于查詢條件錯誤、查詢字段不存在或其他原因導緻查詢出錯。此時,可以使用MongoDB提供的異常處理機制來捕獲異常,并進行相應的處理。
  • 資料庫連接配接失敗:在連接配接MongoDB資料庫時,可能會由于網絡問題、資料庫服務未啟動或其他原因導緻連接配接失敗。此時,需要檢查資料庫服務是否正常運作,并重新連接配接資料庫。
  • 資料庫連接配接斷開:在MongoDB與用戶端進行通信時,可能會由于網絡問題或者其他原因導緻連接配接斷開。此時,需要重新連接配接MongoDB資料庫,并處理異常情況。
  • 資料庫寫鎖:在進行寫入操作時,可能會由于另一個線程正在寫入同一個文檔而出現寫入鎖。此時,需要等待寫入鎖釋放,然後再進行操作。
  • 資料庫讀鎖:在進行讀取操作時,可能會由于另一個線程正在更新同一個文檔而出現讀取鎖。此時,可以選擇等待讀取鎖釋放,或者強制擷取讀取鎖進行讀取操作。

在進行資料入庫到MongoDB的過程中,可能會遇到各種異常情況,需要注意異常處理,以保證資料的完整性和正确性。需要使用MongoDB提供的異常處理機制,對可能出現的異常進行捕獲,并進行相應的處理。此外,還需要注意在進行寫入操作時可能出現的寫鎖,以及在進行讀取操作時可能出現的讀鎖。

3.爬蟲對接MongoDB實戰操作

在進行爬蟲資料采集時,将采集到的資料存儲到MongoDB資料庫中是一個比較常見的操作。下面簡單介紹一下如何使用Python爬蟲程式對接MongoDB資料庫進行實戰操作。

  • 安裝MongoDB驅動程式:Python爬蟲程式可以使用第三方庫–pymongo–來操作MongoDB資料庫。首先需要安裝pymongo庫,可以使用pip指令進行安裝:
pip install pymongo           
  • 連接配接MongoDB資料庫:使用pymongo庫連接配接MongoDB資料庫非常簡單。需要指定MongoDB伺服器的IP位址及端口号,同時指定要使用的資料庫名稱和集合名稱。示例代碼如下:
import pymongo

# 連接配接MongoDB伺服器
client = pymongo.MongoClient("mongodb://localhost:27017/")

# 選擇資料庫和集合
db = client["testdb"]
col = db["testcol"]           

在實際操作中,可以根據需要自己定義資料庫和集合的名稱。

  • 插入資料到MongoDB:将爬蟲采集到的資料插入到MongoDB中,需要使用pymongo庫提供的insert_one()或insert_many()方法。如果要插入多條資料,可以使用insert_many()方法。示例代碼如下:
import pymongo

# 連接配接MongoDB伺服器
client = pymongo.MongoClient("mongodb://localhost:27017/")

# 選擇資料庫和集合
db = client["testdb"]
col = db["testcol"]

# 插入一條資料
data = {"title": "Python程式設計", "price": 88.8}
col.insert_one(data)

# 插入多條資料
datas = [
    {"title": "Java程式設計", "price": 99.9},
    {"title": "C++程式設計", "price": 79.9},
    {"title": "PHP程式設計", "price": 69.9},
]
col.insert_many(datas)           
  • 查詢資料:查詢MongoDB資料庫中的資料,需要使用pymongo庫提供的find()方法。可以根據需要指定查詢條件和查詢字段。示例代碼如下:
import pymongo

# 連接配接MongoDB伺服器
client = pymongo.MongoClient("mongodb://localhost:27017/")

# 選擇資料庫和集合
db = client["testdb"]
col = db["testcol"]

# 查詢資料
data = col.find_one({"title": "Python程式設計"})
print(data)

for data in col.find():
    print(data)           
  • 更新資料和删除資料:使用pymongo庫提供的update_one()、update_many()、delete_one()和delete_many()方法可以更新和删除MongoDB資料庫中的資料。
import pymongo

# 連接配接MongoDB伺服器
client = pymongo.MongoClient("mongodb://localhost:27017/")

# 選擇資料庫和集合
db = client["testdb"]
col = db["testcol"]

# 更新資料
query = {"title": "Python程式設計"}
new_data = {"$set": {"price": 99.99}}
result = col.update_one(query, new_data)
print(result.modified_count)

# 删除資料
query = {"title": "Python程式設計"}
result = col.delete_one(query)
print(result.deleted_count)           

以上就是對接MongoDB資料庫的實戰操作。需要注意的是,MongoDB資料庫在進行大量寫入資料時,可能會遇到性能瓶頸問題,可以通過使用分片和索引等技術來提高MongoDB資料庫的性能。

三丶JSON

進行資料采集時,一種常見的資料存儲格式是JSON(JavaScript Object Notation)。JSON格式具有輕量級、結構化等優點,且易于使用和解析。下面介紹PC端爬蟲工程師采集資料後如何将資料存儲為JSON格式。

使用Python标準庫json将資料轉換為JSON格式

Python标準庫json提供了loads(),load(),dumps()和dump()四個函數用于JSON資料的解析和編碼。其中,dump()函數可以将Python對象直接序列化為JSON檔案,如下使用示例:

import json

data = {
    "name": "Tom",
    "age": 18,
    "gender": "male"
}

with open("data.json", "w") as f:
    json.dump(data, f)           

使用Python第三方庫pandas将資料存儲為JSON格式

pandas是一種基于NumPy的資料分析工具,支援多種資料格式的解析、操作和存儲,其中就包括JSON格式。pandas提供了to_json()方法,可以将DataFrame對象、Series對象或Python字典對象存儲為JSON格式檔案。示例如下:

import pandas as pd

data = pd.DataFrame({
    "name": ["Tom", "Jack", "Lucy"],
    "age": [18, 19, 20],
    "gender": ["male", "male", "female"]
})

data.to_json("data.json")           

使用Python第三方庫scrapy将資料存儲為JSON格式

scrapy是一種廣泛應用于Web爬蟲資料采集的Python架構,它預設支援多種資料存儲方式,包括JSON格式。在使用scrapy架構進行資料采集時,可以将資料存儲為JSON格式,示例代碼如下:

import scrapy

class MySpider(scrapy.Spider):
    name = "example.com"
    start_urls = ["http://www.example.com"]

    def parse(self, response):
        # 爬蟲采集到的資料
        data = {
            "name": "Tom",
            "age": 18,
            "gender": "male"
        }

        # 将資料存儲為JSON格式
        yield data           

進行資料采集時,可以選擇将采集到的資料存儲為JSON格式。可以使用Python标準庫json、第三方庫pandas或爬蟲架構scrapy提供的方法将資料以JSON格式存儲起來,以達到友善解析和處理的效果。

1.JSON對象和數組

JSON對象

JSON對象是由花括号“{}”包圍的一組屬性-值對。屬性和值之間使用冒号“:”分隔,不同屬性之間使用逗号“,”分隔。一個JSON對象可以包含零到多個屬性-值對,示例如下:

{
    "name": "Tom",
    "age": 18,
    "gender": "male",
    "hobbies": ["reading", "traveling"]
}           

其中,name、age、gender是屬性,對應的值分别是Tom、18、male;hobbies是一個數組,包含兩個元素reading和traveling。

JSON數組

JSON數組是由方括号“[]”包圍的一組值,不同值之間使用逗号“,”分隔。一個JSON數組可以包含零到多個值,示例如下:

[
    {"name": "Tom", "age": 18, "gender": "male"},
    {"name": "Jack", "age": 19, "gender": "male"},
    {"name": "Lucy", "age": 20, "gender": "female"}
]           

這是一個包含三個JSON對象的數組,每個對象都包括name、age、gender三個屬性,分别表示姓名、年齡、性别。

使用JSON對象和JSON數組可以靈活地組織和存儲資料。在進行資料采集和資料處理時,PC端爬蟲工程師需要了解和掌握這兩種JSON結構的相關知識,以便更好地将采集到的資料存儲為JSON格式,進行資料解析和處理等操作。

2.JSON資料編碼

進行資料采集和資料存儲時,需要将采集到的資料編碼為JSON格式,以便後續進行解析和處理等操作。在Python語言中,使用json子產品可以友善地進行JSON資料編碼。

具體操作如下:

導入json子產品:

import json           

将Python資料類型轉換為JSON格式:

使用json.dump()方法,将Python資料類型(如字典、清單)轉換為JSON格式,并存儲到指定檔案中。文法如下:

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)           

其中,參數obj為Python資料類型,參數f為檔案路徑。

代碼示例:

import json

data = {"name": "Tom", "age": 18, "gender": "male"}

with open("data.json", "w") as f:
    json.dump(data, f)           

運作代碼後,會在目前工作目錄中生成一個data.json檔案,檔案内容為轉換後的JSON格式資料:

{"name": "Tom", "age": 18, "gender": "male"}           

将Python資料類型轉換為JSON格式,傳回JSON字元串:

使用json.dumps()方法,将Python資料類型(如字典、清單)轉換為JSON格式,并傳回一個對應的JSON字元串。文法如下:

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)           

其中,參數obj為Python資料類型。

代碼示例:

import json

data = {"name": "Tom", "age": 18, "gender": "male"}

json_str = json.dumps(data)

print(json_str)           

運作代碼後,控制台會輸出轉換後的JSON格式字元串:

{"name": "Tom", "age": 18, "gender": "male"}           

可以根據實際情況選擇使用json.dump()或json.dumps()進行JSON資料編碼,以便将采集到的資料存儲為JSON格式,友善後續的資料處理和解析等操作。

從零開始學python(十二)如何成為一名優秀的爬蟲工程師

适用于零基礎學習和進階人群的python資源:

① 騰訊認證python完整項目實戰教程筆記PDF

② 十幾個大廠python面試專題PDF

③ python全套視訊教程(零基礎-進階進階JS逆向)

④ 百個項目實戰+源碼+筆記

⑤ 程式設計文法-機器學習-全棧開發-資料分析-爬蟲-APP逆向等全套項目+文檔

python教程+源碼+學習筆記