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

前言

回顧之前講述了python語法編程 必修入門基礎(chǔ)和網(wǎng)絡(luò)編程,多線程/多進(jìn)程/協(xié)程等方面的內(nèi)容瓣铣,后續(xù)講到了數(shù)據(jù)庫編程篇MySQL,Redis贷揽,MongoDB篇棠笑,和機器學(xué)習(xí),全棧開發(fā)禽绪,數(shù)據(jù)分析前面沒看的也不用往前翻蓖救,系列文已經(jīng)整理好了:


1.跟我一起從零開始學(xué)python(一)編程語法必修
2.跟我一起從零開始學(xué)python(二)網(wǎng)絡(luò)編程
3.跟我一起從零開始學(xué)python(三)多線程/多進(jìn)程/協(xié)程
4.跟我一起從零開始學(xué)python(四)數(shù)據(jù)庫編程:MySQL數(shù)據(jù)庫
5.跟我一起從零開始學(xué)python(五)數(shù)據(jù)庫編程:Redis數(shù)據(jù)庫
6.跟我一起從零開始學(xué)python(六)數(shù)據(jù)庫編程:MongoDB數(shù)據(jù)庫
7.跟我一起從零開始學(xué)python(七)機器學(xué)習(xí)
8.跟我一起從零開始學(xué)python(八)全棧開發(fā)
9.跟我一起從零開始學(xué)python(九)數(shù)據(jù)分析
10.跟我一起從零開始學(xué)python(十)Hadoop從零開始入門
11.跟我一起從零開始學(xué)python(十一)簡述spark

本系列文根據(jù)以下學(xué)習(xí)路線展開講述,由于內(nèi)容較多印屁,:

從零開始學(xué)python到高級進(jìn)階路線圖

一丶采集功底專題

1.網(wǎng)絡(luò)請求

網(wǎng)絡(luò)請求是爬蟲工程師采集數(shù)據(jù)的重要手段之一循捺。在PC端爬蟲中,網(wǎng)絡(luò)請求通常使用HTTP協(xié)議進(jìn)行通信雄人,通過發(fā)送HTTP請求獲取目標(biāo)網(wǎng)站的數(shù)據(jù)从橘。

爬蟲工程師需要掌握HTTP協(xié)議的基本知識,包括HTTP請求和響應(yīng)的格式础钠、常見的HTTP請求方法(如GET洋满、POST等)、HTTP請求頭和響應(yīng)頭的常見字段等珍坊。

在進(jìn)行網(wǎng)絡(luò)請求時,爬蟲工程師通常使用HTTP客戶端庫正罢,如Python中的requests庫阵漏、Java中的HttpClient等。這些庫封裝了HTTP協(xié)議的細(xì)節(jié)翻具,提供了簡單易用的API履怯,方便爬蟲工程師進(jìn)行網(wǎng)絡(luò)請求。

爬蟲工程師還需要了解一些反爬蟲技術(shù)裆泳,如User-Agent偽裝叹洲、IP代理等,以應(yīng)對目標(biāo)網(wǎng)站的反爬蟲策略工禾。

一丶requests

1.requests源碼解析

對于爬蟲工程師來說运提,網(wǎng)絡(luò)請求是常用的數(shù)據(jù)采集方式之一蝗柔。而Python的requests庫,作為一個高效且易用的HTTP請求庫民泵,被爬蟲工程師廣泛使用癣丧。在深入學(xué)習(xí)requests庫前,建議先了解下其中的源碼實現(xiàn)栈妆。

requests庫是基于urllib3庫封裝的胁编,所以在使用requests庫時需要先安裝對應(yīng)的依賴庫urllib3。

接下來鳞尔,我們通過分析requests庫的源代碼嬉橙,來了解其中的一些實現(xiàn)細(xì)節(jié)。

首先是發(fā)送請求的實現(xiàn)寥假,即requests庫中的Request類市框。Request類用于封裝發(fā)送請求的參數(shù),并通過一個Session對象發(fā)送請求并返回響應(yīng)昧旨。以下是Request類的核心代碼:

class Request:

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

我們可以看到拾给,Request類中的send方法調(diào)用了Session對象的request方法,這個方法是整個庫中負(fù)責(zé)發(fā)送請求和返回響應(yīng)的核心方法兔沃。以下是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方法的參數(shù)和關(guān)鍵字參數(shù)與HTTP請求的相關(guān)部分一一對應(yīng),其中最重要的是prep參數(shù)(即經(jīng)過預(yù)處理的Request對象)乒疏,它包含了請求的相關(guān)信息额衙,如請求方法,請求頭怕吴,請求體等窍侧。Session對象的request方法最終調(diào)用了self.send方法,即發(fā)送HTTP請求并返回響應(yīng)转绷。

requests庫實現(xiàn)了帶有各種HTTP請求方法的函數(shù)接口伟件,如requests.get()requests.post()等议经,這些接口在內(nèi)部會自動創(chuàng)建一個Session對象斧账,然后調(diào)用Session對象的request方法,從而返回請求響應(yīng)煞肾。

總體來說咧织,requests是一個功能強大的HTTP請求庫,它的源代碼實現(xiàn)清晰籍救、易于閱讀和理解习绢,掌握其中的實現(xiàn)細(xì)節(jié)可以幫助我們更好的使用這個庫。

2.requests常用方法

requests是一個Python第三方庫蝙昙,用于發(fā)送HTTP請求闪萄。以下是requests常用方法:

  • requests.get(url, params=None, **kwargs):發(fā)送GET請求梧却,url為請求的URL地址,params為請求參數(shù)桃煎,kwargs為其他可選參數(shù)篮幢。

  • requests.post(url, data=None, json=None, **kwargs):發(fā)送POST請求,url為請求的URL地址为迈,data為請求數(shù)據(jù)三椿,json為請求的JSON數(shù)據(jù),**kwargs為其他可選參數(shù)葫辐。

  • requests.put(url, data=None, **kwargs):發(fā)送PUT請求搜锰,url為請求的URL地址,data為請求數(shù)據(jù)耿战,**kwargs為其他可選參數(shù)蛋叼。

  • requests.delete(url, **kwargs):發(fā)送DELETE請求,url為請求的URL地址剂陡,**kwargs為其他可選參數(shù)狈涮。

  • requests.head(url, **kwargs):發(fā)送HEAD請求,url為請求的URL地址鸭栖,**kwargs為其他可選參數(shù)歌馍。

  • requests.options(url, **kwargs):發(fā)送OPTIONS請求,url為請求的URL地址晕鹊,**kwargs為其他可選參數(shù)松却。

  • requests.request(method, url, **kwargs):發(fā)送自定義請求,method為請求方法溅话,url為請求的URL地址晓锻,**kwargs為其他可選參數(shù)。

  • requests.session():創(chuàng)建一個Session對象飞几,用于保持會話狀態(tài)砚哆。

  • requests.get(url, headers=headers):發(fā)送GET請求,并設(shè)置請求頭屑墨。

  • requests.get(url, cookies=cookies):發(fā)送GET請求躁锁,并設(shè)置請求的Cookies

  • requests.get(url, proxies=proxies):發(fā)送GET請求绪钥,并設(shè)置代理服務(wù)器。

  • requests.get(url, timeout=timeout):發(fā)送GET請求关炼,并設(shè)置超時時間程腹。

  • requests.get(url, verify=verify):發(fā)送GET請求,并設(shè)置SSL證書驗證儒拂。

  • requests.get(url, allow_redirects=allow_redirects):發(fā)送GET請求寸潦,并設(shè)置是否允許重定向色鸳。

  • requests.get(url, stream=stream):發(fā)送GET請求,并設(shè)置是否使用流式傳輸

3.data/json/param參數(shù)傳遞

在使用requests庫發(fā)送網(wǎng)絡(luò)請求時见转,我們可以通過傳遞不同的參數(shù)來實現(xiàn)不同的請求方式和數(shù)據(jù)傳遞方式命雀。常用的參數(shù)包括data、json和params斩箫。

1.data參數(shù)

data參數(shù)用于傳遞表單數(shù)據(jù)吏砂,通常用于POST請求。它可以是一個字典乘客,也可以是一個字符串狐血。如果是字典,requests會自動將其轉(zhuǎn)換為表單形式易核;如果是字符串匈织,則需要手動指定Content-Typeapplication/x-www-form-urlencoded

示例代碼:

import requests

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

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

2.json參數(shù)

json參數(shù)用于傳遞JSON格式的數(shù)據(jù)牡直,通常用于POST請求缀匕。它可以是一個字典,也可以是一個字符串碰逸。如果是字典乡小,requests會自動將其轉(zhuǎn)換為JSON格式;如果是字符串花竞,則需要手動指定Content-Typeapplication/json劲件。

示例代碼:

import requests

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

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

3.params參數(shù)

params參數(shù)用于傳遞URL參數(shù),通常用于GET請求约急。它可以是一個字典零远,也可以是一個字符串。如果是字典厌蔽,requests會自動將其轉(zhuǎn)換為URL參數(shù)牵辣;如果是字符串,則需要手動拼接URL奴饮。

示例代碼:

import requests

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

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

4.隧道代理使用

隧道代理是一種通過隧道連接到代理服務(wù)器的方式來進(jìn)行網(wǎng)絡(luò)請求的方法纬向。這種方式可以幫助我們隱藏真實的IP地址,提高爬蟲的穩(wěn)定性和安全性戴卜。

使用隧道代理需要先購買代理服務(wù)逾条,然后在代碼中設(shè)置代理服務(wù)器的IP地址和端口號。以下是一個使用隧道代理的示例代碼:

import requests

proxy = {
    'http': 'http://代理服務(wù)器IP地址:端口號',
    'https': 'https://代理服務(wù)器IP地址:端口號'
}

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

print(response.text)

在上面的代碼中投剥,我們首先定義了一個代理字典师脂,包含了http和https兩種協(xié)議的代理服務(wù)器地址和端口號。然后使用requests庫的get方法發(fā)送請求時,將代理字典作為proxies參數(shù)傳入即可吃警。

需要注意的是糕篇,使用隧道代理可能會降低請求速度呐粘,而且代理服務(wù)的質(zhì)量也會影響到爬蟲的效果危虱。因此,在選擇代理服務(wù)時需要謹(jǐn)慎酗失,建議選擇穩(wěn)定可靠的服務(wù)商安券。

5.證書異常處理

在進(jìn)行網(wǎng)絡(luò)請求時墩崩,有些網(wǎng)站會進(jìn)行證書認(rèn)證以確保數(shù)據(jù)的安全。如果requests庫在進(jìn)行SSL證書驗證時遇到了問題完疫,會拋出“證書驗證異常(Certificate Verification Error)”的異常泰鸡。這個異常通常是由于請求響應(yīng)的SSL證書無效或不受信任導(dǎo)致的。

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

1.忽略證書驗證

在使用requests庫進(jìn)行網(wǎng)絡(luò)請求時壳鹤,可以通過設(shè)置verify參數(shù)為False來忽略SSL證書驗證盛龄。這個方法會禁止requests庫對證書進(jìn)行驗證,而是采用不安全的方式進(jìn)行通信芳誓,因此在進(jìn)行敏感操作時應(yīng)慎重使用余舶。

例如:

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

2.設(shè)置證書文件

可以通過設(shè)置cert參數(shù)來指定一個證書文件,在請求時使用該證書進(jìn)行驗證锹淌。這個方法需要事先獲得一個有效的證書文件匿值,如果無法提供有效證書則無法進(jìn)行安全通信。

例如:

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

3.添加自定義證書

可以通過requests庫提供的certifi庫在運行時初始化一個自定義證書赂摆,從而進(jìn)行證書驗證挟憔。這種方式需要提供證書的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()用于獲取當(dāng)前Python環(huán)境中的證書路徑,然后將每個需要驗證的主機和其證書的SHA256指紋添加到證書文件中汪拥。

綜上达传,要避免證書異常需要注意常見的安全規(guī)則,如設(shè)置SSL證書驗證迫筑、使用CA頒發(fā)的證書宪赶、對外不開放不安全的通信端口等。需要快速掃描設(shè)備脯燃,確保組件升級到最新版本搂妻,在安全上下文中測試企業(yè)所依賴的所有服務(wù)并采用有力的加密技術(shù)以支持加密通信。

二丶httpx

1.httpx源碼解析

httpx是一個Python異步HTTP客戶端庫辕棚,它提供了簡單易用的API欲主,支持異步和同步請求追他,支持HTTP/1.1和HTTP/2協(xié)議,支持代理岛蚤、SSL/TLS、Cookie等功能懈糯。下面我們來看一下httpx的源碼解析涤妒。

httpx的核心代碼在client.py文件中,其中最重要的是Client類赚哗。Client類是httpx的主要接口她紫,它提供了發(fā)送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類的構(gòu)造函數(shù)接受很多參數(shù)民褂,這些參數(shù)可以用來配置httpx的行為。其中比較重要的參數(shù)包括:

  • timeout:請求超時時間疯潭。
  • follow_redirects:是否自動跟隨重定向赊堪。
  • max_redirects:最大重定向次數(shù)。
  • verify:是否驗證SSL證書竖哩。
  • cert:客戶端證書哭廉。
  • trust_env:是否信任環(huán)境變量。
  • http2:是否啟用HTTP/2協(xié)議相叁。
  • backend:HTTP客戶端后端遵绰。
  • default_headers:默認(rèn)請求頭。
  • base_url:基礎(chǔ)URL增淹。
  • app:ASGI應(yīng)用程序椿访。
  • auth:HTTP認(rèn)證。
  • cookies:請求Cookie埠通。
  • allow_redirects:是否允許重定向赎离。
  • proxies:代理服務(wù)器。
  • dispatch:請求分發(fā)器端辱。
  • limits:請求限制梁剔。
  • pool_limits:連接池限制。
  • retry:請求重試舞蔽。
  • trust_env_proxies:是否信任環(huán)境變量中的代理服務(wù)器荣病。
  • headers:請求頭。

Client類的方法包括

  • request:發(fā)送HTTP請求渗柿。
  • get:發(fā)送GET請求个盆。
  • post:發(fā)送POST請求脖岛。
  • put:發(fā)送PUT請求。
  • delete:發(fā)送DELETE請求颊亮。
  • head:發(fā)送HEAD請求柴梆。
  • options:發(fā)送OPTIONS請求。
  • patch:發(fā)送PATCH請求终惑。
    這些方法都是基于request方法實現(xiàn)的绍在,只是參數(shù)不同。下面是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方法接受很多參數(shù)雹有,包括HTTP請求方法偿渡、URL、請求參數(shù)霸奕、請求體溜宽、請求頭、請求Cookie质帅、文件适揉、HTTP認(rèn)證、請求超時時間煤惩、是否允許重定向涡扼、客戶端證書、是否驗證SSL證書盟庞、是否使用流式傳輸吃沪、是否信任環(huán)境變量、最大重定向次數(shù)什猖、是否啟用HTTP/2協(xié)議票彪、HTTP客戶端后端、請求分發(fā)器不狮、請求限制降铸、連接池限制、請求重試摇零、是否信任環(huán)境變量中的代理服務(wù)器等推掸。

httpx的源碼比較清晰,代碼結(jié)構(gòu)清晰驻仅,注釋詳細(xì)谅畅,易于閱讀和理解。如果你想深入了解httpx的實現(xiàn)原理噪服,可以閱讀httpx的源碼毡泻。

2.httpx常用方法

httpx是一個Python的異步HTTP客戶端庫,它提供了許多常用的方法來發(fā)送HTTP請求和處理響應(yīng)粘优。以下是httpx常用的方法:

  • get(url, params=None, **kwargs): 發(fā)送GET請求仇味,url為請求的URL呻顽,params為請求參數(shù),kwargs為其他可選參數(shù)丹墨,如headers廊遍、timeout等。

  • post(url, data=None, json=None, **kwargs): 發(fā)送POST請求贩挣,url為請求的URL昧碉,data為請求數(shù)據(jù),json為請求的JSON數(shù)據(jù)揽惹,kwargs為其他可選參數(shù),如headers四康、timeout等搪搏。

  • put(url, data=None, **kwargs): 發(fā)送PUT請求,url為請求的URL闪金,data為請求數(shù)據(jù)疯溺,kwargs為其他可選參數(shù),如headers哎垦、timeout等囱嫩。

  • delete(url, **kwargs): 發(fā)送DELETE請求,url為請求的URL漏设,kwargs為其他可選參數(shù)墨闲,如headers、timeout等郑口。

  • head(url, **kwargs): 發(fā)送HEAD請求鸳碧,url為請求的URL,kwargs為其他可選參數(shù)犬性,如headers瞻离、timeout等。

  • options(url, **kwargs): 發(fā)送OPTIONS請求乒裆,url為請求的URL套利,kwargs為其他可選參數(shù),如headers鹤耍、timeout等肉迫。

  • request(method, url, **kwargs): 發(fā)送自定義請求,method為請求方法稿黄,url為請求的URL昂拂,kwargs為其他可選參數(shù),如headers抛猖、timeout等格侯。

  • close(): 關(guān)閉httpx客戶端鼻听。

  • request_stream(method, url, **kwargs): 發(fā)送流式請求,method為請求方法联四,url為請求的URL撑碴,kwargs為其他可選參數(shù),如headers朝墩、timeout等醉拓。

  • request_raw(method, url, **kwargs): 發(fā)送原始請求,method為請求方法收苏,url為請求的URL亿卤,kwargs為其他可選參數(shù),如headers鹿霸、timeout等排吴。

  • request_bytes(method, url, **kwargs): 發(fā)送字節(jié)請求,method為請求方法懦鼠,url為請求的URL钻哩,kwargs為其他可選參數(shù),如headers肛冶、timeout等街氢。

  • request_json(method, url, **kwargs): 發(fā)送JSON請求,method為請求方法睦袖,url為請求的URL珊肃,kwargs為其他可選參數(shù),如headers馅笙、timeout等近范。

  • request_text(method, url, **kwargs): 發(fā)送文本請求,method為請求方法延蟹,url為請求的URL评矩,kwargs為其他可選參數(shù),如headers阱飘、timeout等斥杜。

  • request_files(method, url, files=None, **kwargs): 發(fā)送文件請求,method為請求方法沥匈,url為請求的URL蔗喂,files為上傳的文件,kwargs為其他可選參數(shù)高帖,如headers缰儿、timeout等。

  • request_multipart(method, url, data=None, files=None, **kwargs): 發(fā)送多部分請求散址,method為請求方法乖阵,url為請求的URL宣赔,data為請求數(shù)據(jù),files為上傳的文件瞪浸,kwargs為其他可選參數(shù)儒将,如headers、timeout等对蒲。

3.httpx上下文處理

在httpx中钩蚊,上下文處理是指在一個請求中,將一些共同的參數(shù)或配置信息保存在一個上下文對象中蹈矮,以便在后續(xù)的請求中使用砰逻。這樣可以避免在每個請求中都重復(fù)設(shè)置相同的參數(shù)或配置信息,提高代碼的可讀性和可維護(hù)性泛鸟。

httpx中的上下文對象是一個字典,可以通過創(chuàng)建一個httpx.Context對象來獲取。在創(chuàng)建Context對象時碑韵,可以傳入一些默認(rèn)的參數(shù)或配置信息,這些信息會被保存在Context對象中,以便在后續(xù)的請求中使用遗菠。

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

1.創(chuàng)建Context對象

import httpx

context = httpx.Context()

2.設(shè)置默認(rèn)的請求頭

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.設(shè)置代理

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

4.設(shè)置超時時間

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

5.設(shè)置SSL驗證

context.verify = False

6.設(shè)置cookie

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

7.設(shè)置認(rèn)證信息

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

8.設(shè)置重試次數(shù)

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

9.設(shè)置連接池

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異步請求

在進(jìn)行網(wǎng)絡(luò)請求時,有時候需要進(jìn)行異步請求,以提高效率和性能蓖谢。httpx是一個支持異步請求的Python HTTP客戶端庫,可以使用async/await語法進(jìn)行異步請求盯腌。

下面是一個使用httpx進(jìn)行異步請求的示例:

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函數(shù),用于異步請求指定的URL,并返回響應(yīng)內(nèi)容恒傻。然后在main函數(shù)中,我們定義了三個URL沸手,使用asyncio.create_task創(chuàng)建了三個異步任務(wù)诡渴,并使用asyncio.gather等待所有任務(wù)完成,并打印結(jié)果鸭津。

需要注意的是潭辈,在使用httpx進(jìn)行異步請求時,需要使用AsyncClient類修赞,而不是普通的Client類勾邦。此外,需要使用async/await語法進(jìn)行異步請求。

2.數(shù)據(jù)解析

數(shù)據(jù)解析是爬蟲工程師采集數(shù)據(jù)的重要環(huán)節(jié)昧港,它的目的是從爬取到的網(wǎng)頁中提取出需要的數(shù)據(jù)。常用的數(shù)據(jù)解析方法有正則表達(dá)式、XPath、BeautifulSoup等稽坤。

其中睦擂,正則表達(dá)式是一種強大的文本匹配工具淘正,可以用來匹配和提取文本中的特定模式述呐。在爬蟲中思犁,正則表達(dá)式通常用于匹配HTML標(biāo)簽中的內(nèi)容棉磨,例如匹配網(wǎng)頁中的標(biāo)題、鏈接、圖片等差油。

正則表達(dá)式的基本語法包括字符集、量詞、分組、反向引用等见秽。例如返顺,要匹配一個HTML標(biāo)簽中的鏈接振乏,可以使用以下正則表達(dá)式:

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

其中,\s+表示匹配一個或多個空格旧噪,["']表示匹配單引號或雙引號,[^"']+表示匹配除了單引號和雙引號以外的任意字符,.*?表示匹配任意字符铁瞒,但是盡可能少地匹配丐谋。

在使用正則表達(dá)式進(jìn)行數(shù)據(jù)解析時泌豆,需要注意以下幾點:

  • 正則表達(dá)式的語法較為復(fù)雜猪落,需要仔細(xì)學(xué)習(xí)和理解兴革。
  • 正則表達(dá)式的性能較差庶艾,對于大規(guī)模數(shù)據(jù)解析可能會影響爬蟲的效率。
  • 正則表達(dá)式只能匹配文本掩完,對于非文本數(shù)據(jù)(如圖片、視頻等)無法處理。

因此焦匈,在實際爬蟲開發(fā)中摔笤,需要根據(jù)具體情況選擇合適的數(shù)據(jù)解析方法版述。

一丶正則表達(dá)式

1.正則原理概述

在爬蟲中吮龄,數(shù)據(jù)解析是非常重要的一環(huán)母债,因為數(shù)據(jù)解析模塊的好壞將直接決定了爬蟲的效率和準(zhǔn)確度昧辽。正則表達(dá)式是數(shù)據(jù)解析中常用的一種技術(shù)红氯,下面就來簡要介紹一下正則表達(dá)式的原理。

正則表達(dá)式(Regular Expression)即為正則或稱規(guī)則表達(dá)式,是一套用于描述、匹配和處理文本的符號規(guī)則。在爬蟲中绷雏,正則表達(dá)式常被用于從HTML文本中提取出我們需要的數(shù)據(jù)兴猩。正則表達(dá)式的語法非常強大,包括字符集潭千、元字符路翻、量詞嘹黔、分組等許多特性郭蕉,能夠滿足各種復(fù)雜的匹配需求。下面簡要介紹一些正則表達(dá)式的語法:

字符集

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

元字符

元字符(Metacharacters)是正則表達(dá)式中具有特殊含義的字符锨能,如 \倔约、^、$、*樱哼、+呼胚、?、.常遂、|克胳、()平绩、{m,n} 等等。這些字符在正則表達(dá)式中并非表示字面意義漠另,而是具有某種特殊的含義。

量詞

量詞用于指定字符或子表達(dá)式出現(xiàn)的次數(shù)笆搓,常用的量詞包括:

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

分組

分組用小括號括起來,用于將多個部分組合在一起满败。分組還允許應(yīng)用量詞肤频,即在一個組內(nèi)表示一定數(shù)量的字符。

當(dāng)然算墨,正則表達(dá)式也存在一些限制宵荒。由于正則表達(dá)式本身較為復(fù)雜,容易出現(xiàn)邏輯上的錯誤净嘀,在使用時需要注意报咳。此外,在處理海量數(shù)據(jù)時挖藏,正則表達(dá)式的效率可能會成為影響程序性能的瓶頸暑刃。

綜上所述,正則表達(dá)式是數(shù)據(jù)解析中非常常用的一種技術(shù)膜眠,掌握正則表達(dá)式的語法規(guī)則稍走,能夠更方便地從HTML文本中提取出所需的數(shù)據(jù)。

2.分組和通用匹配

正則表達(dá)式是一種用于匹配文本的工具柴底,它可以用來解析HTML婿脸、XML等文本格式的數(shù)據(jù)。在正則表達(dá)式中柄驻,分組和通用匹配是兩個常用的概念狐树。

1.分組

分組是指將正則表達(dá)式中的一部分用括號括起來,形成一個子表達(dá)式鸿脓。分組可以用來限定匹配范圍抑钟、提取匹配結(jié)果等涯曲。

例如,正則表達(dá)式<a href="(.?)">(.?)</a>中在塔,用括號括起來的部分就是分組幻件,第一個分組(.?)用來匹配鏈接地址,第二個分組(.?)用來匹配鏈接文本蛔溃。

2.通用匹配

通用匹配是指用.來匹配任意字符的正則表達(dá)式绰沥。通用匹配可以用來匹配一些不確定的字符,例如空格贺待、換行符等徽曲。

例如,正則表達(dá)式<a href=".?">.?</a>中麸塞,用.來匹配鏈接地址和鏈接文本中間的任意字符秃臣,這樣就可以匹配包含任意字符的鏈接了。

需要注意的是哪工,通用匹配可能會匹配到一些不需要的字符奥此,因此在使用時需要謹(jǐn)慎。

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

在爬蟲工程師的采集工作中雁比,數(shù)據(jù)解析是非常重要的一環(huán)節(jié)稚虎。正則表達(dá)式是一種強大的工具,可以用于從網(wǎng)頁中提取有用的信息章贞。在正則表達(dá)式中祥绞,貪婪和非貪婪模式是一個關(guān)鍵的概念,因為它們直接影響到正則表達(dá)式的匹配結(jié)果鸭限。

正則表達(dá)式中的貪婪模式指的是匹配盡可能多的字符蜕径,而非貪婪模式則是匹配盡可能少的字符。默認(rèn)情況下败京,正則表達(dá)式是貪婪的兜喻,這意味著它會嘗試匹配盡可能多的字符。例如赡麦,考慮以下正則表達(dá)式:

.*hello.*

該正則表達(dá)式將匹配任何字符串朴皆,只要它包含子字符串“hello”。但是泛粹,如果我們使用該正則表達(dá)式對以下字符串進(jìn)行匹配:

"hello world! hello goup!"

結(jié)果將是整個字符串遂铡,而不僅僅是第一個“hello”字符串。這是因為正則表達(dá)式會貪婪地匹配盡可能多的字符晶姊,直到找到最后一個“hello”扒接。

要使用非貪婪模式,可以在正則表達(dá)式中使用“?”符號钾怔。例如碱呼,如果我們想要上面的正則表達(dá)式只匹配第一個“hello”,可以這樣寫:

.*?hello.*

這個正則表達(dá)式將會匹配到第一個“hello”宗侦,因為它使用了非貪婪模式愚臀,盡可能少地匹配字符,直到找到第一個“hello”矾利。

總的來說姑裂,在數(shù)據(jù)解析和爬蟲采集過程中,要根據(jù)需要選擇合適的正則表達(dá)式模式梦皮。如果需要匹配盡可能多的字符炭分,則應(yīng)該使用貪婪模式桃焕;如果需要匹配盡可能少的字符剑肯,則應(yīng)該使用非貪婪模式。很多時候观堂,貪婪模式會導(dǎo)致意外的匹配結(jié)果让网,因此需要特別小心。

4.findall/match/search方法

在Python中师痕,re模塊提供了三種方法來匹配正則表達(dá)式:findall溃睹、match和search。

findall方法

findall方法可以在字符串中查找所有匹配正則表達(dá)式的子串胰坟,并返回一個列表因篇。例如:

import re

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

輸出結(jié)果為:

['john@example.com']

match方法

match方法只能在字符串的開頭匹配正則表達(dá)式,如果匹配成功笔横,則返回一個匹配對象竞滓,否則返回None。例如:

import re

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

輸出結(jié)果為:

No match

因為正則表達(dá)式\b\w+@\w+.\w+\b只能匹配單詞邊界處的郵箱地址吹缔,而字符串的開頭不是單詞邊界商佑。

search方法

search方法可以在字符串中查找第一個匹配正則表達(dá)式的子串,并返回一個匹配對象厢塘,否則返回None茶没。例如:

import re

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

輸出結(jié)果為:

john@example.com

因為search方法會在整個字符串中查找匹配正則表達(dá)式的子串。

二丶xpath

XPath是一種用于在XML文檔中定位元素和屬性的語言晚碾,也可以用于HTML文檔的解析抓半。在PC端爬蟲工程師采集數(shù)據(jù)時,XPath可以幫助我們快速準(zhǔn)確地定位到需要的數(shù)據(jù)格嘁。

XPath的語法比較簡單笛求,主要由路徑表達(dá)式和基本表達(dá)式組成。路徑表達(dá)式用于定位元素,基本表達(dá)式用于定位屬性或文本涣易。

以下是一些常用的XPath表達(dá)式:

定位元素

  • //tagname:選取所有名稱為tagname的元素

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

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

定位屬性

  • //@attribute:選取所有名稱為attribute的屬性

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

定位文本

  • //tagname/text():選取所有名稱為tagname的元素的文本內(nèi)容

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

XPath的使用需要借助解析庫画机,比如Python中的lxml庫。使用lxml庫可以通過xpath()方法來解析HTML或XML文檔新症,獲取需要的數(shù)據(jù)步氏。

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

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)

輸出結(jié)果為:

'wd'

這里使用了xpath表達(dá)式//input[@id="kw"]/@name來定位搜索框元素的名稱屬性徒爹。

1.dom節(jié)點

在使用XPath進(jìn)行數(shù)據(jù)解析時荚醒,需要了解DOM節(jié)點的概念。

DOM(Document Object Model)是一種用于表示和操作HTML或XML文檔的標(biāo)準(zhǔn)對象模型隆嗅。在DOM中界阁,文檔被表示為一個樹形結(jié)構(gòu),每個節(jié)點都是一個對象胖喳,包含了文檔中的元素泡躯、屬性、文本等信息丽焊。

在XPath中较剃,每個節(jié)點都有一個節(jié)點類型,常見的節(jié)點類型包括:

  • 元素節(jié)點(Element Node):表示XML或HTML文檔中的元素技健,如<div>写穴、<p>等。
  • 屬性節(jié)點(Attribute Node):表示XML或HTML文檔中的屬性雌贱,如class啊送、id等。
  • 文本節(jié)點(Text Node):表示XML或HTML文檔中的文本內(nèi)容欣孤,如<div>hello world</div>中的hello world馋没。

在XPath中,可以使用不同的語法來選擇DOM節(jié)點导街,常見的語法包括:

  • 路徑表達(dá)式(Path Expression):使用路徑表達(dá)式可以選擇文檔中的某個節(jié)點或一組節(jié)點披泪。例如,選擇所有的<div>元素可以使用路徑表達(dá)式//div搬瑰。
  • 軸(Axis):軸是一種用于選擇節(jié)點的方法款票,可以選擇與當(dāng)前節(jié)點有特定關(guān)系的節(jié)點。例如泽论,選擇當(dāng)前節(jié)點的所有子節(jié)點可以使用軸child::艾少。
  • 謂語(Predicate):謂語是一種用于過濾節(jié)點的方法,可以根據(jù)節(jié)點的屬性或位置等信息來選擇節(jié)點翼悴。例如缚够,選擇第一個<div>元素可以使用路徑表達(dá)式(//div)[1]幔妨。

掌握DOM節(jié)點的概念和XPath的語法,可以更加靈活地進(jìn)行數(shù)據(jù)解析谍椅。

2.xpath語法學(xué)習(xí)

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

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

  • 節(jié)點:XML文檔中的元素雏吭、屬性等都是節(jié)點锁施。
  • 路徑表達(dá)式:一種用來表示選擇某個節(jié)點或一組節(jié)點的字符串。
  • 路徑:路徑指定從文檔根節(jié)點到所選節(jié)點的方式杖们,可以是絕對路徑或相對路徑悉抵。
  • 謂語:謂語用于篩選節(jié)點,可以是一個表達(dá)式或條件摘完。

XPath語法示例:

選擇節(jié)點

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

選擇屬性

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

謂語

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

XPath的語法非常直觀姥饰,容易理解和記憶揩魂。在使用XPath語法進(jìn)行數(shù)據(jù)解析時谆甜,可以使用Python中的lxml庫來實現(xiàn)耘成,使用方法也非常簡單玷室。使用lxml庫和XPath語法,可以將HTML或XML文檔中的數(shù)據(jù)提取出來并保存為結(jié)構(gòu)化數(shù)據(jù)米奸,用于后續(xù)的分析和處理毙籽。

3.xpath定位文章數(shù)據(jù)

在使用XPath定位文章數(shù)據(jù)時,需要先用瀏覽器開發(fā)者工具分析文章頁面的HTML結(jié)構(gòu)步绸,找出要提取的數(shù)據(jù)所在的節(jié)點,然后使用XPath語法來篩選這些節(jié)點吃媒。

以下是一個示例瓤介,假設(shè)我們要從一個博客的文章頁面中提取文章標(biāo)題、作者赘那、發(fā)布時間和正文:

<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語法刑桑,可以定位到需要提取的節(jié)點:

//h1[@class='title']  # 定位到文章標(biāo)題節(jié)點
//p[@class='author']  # 定位到作者節(jié)點
//p[@class='publish-time']  # 定位到發(fā)布時間節(jié)點
//div[@class='content']/p  # 定位到正文每一段的節(jié)點

然后使用Python中的lxml庫解析HTML,提取出這些節(jié)點的文本內(nèi)容:

from lxml import etree

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

# 提取節(jié)點文本
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祠斧、authorpublish_time為字符串,content為字符串列表拱礁,每個元素為正文中的一段琢锋。后面可以根據(jù)需要將這些數(shù)據(jù)保存到文件或數(shù)據(jù)庫中,或者進(jìn)行其他的數(shù)據(jù)處理呢灶。

三丶Beautiful

在進(jìn)行網(wǎng)頁數(shù)據(jù)解析時吴超,我們需要使用一些工具來幫助我們快速地定位和提取所需的數(shù)據(jù)。其中鸯乃,Beautiful Soup是一個非常常用的Python庫鲸阻,它可以幫助我們解析HTML和XML文檔,并提供了一些方便的方法來定位和提取數(shù)據(jù)。

安裝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>歡迎來到我的網(wǎng)站</h1>
    <p class="content">這是一個示例頁面揍堰,用于演示Beautiful Soup的使用方法鹏浅。</p>
    <ul>
        <li><a >鏈接1</a></li>
        <li><a >鏈接2</a></li>
        <li><a >鏈接3</a></li>
    </ul>
</body>
</html>
"""

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

在這個例子中,我們首先定義了一個HTML文檔的字符串屏歹,然后使用Beautiful Soup的構(gòu)造函數(shù)來創(chuàng)建一個BeautifulSoup對象隐砸。構(gòu)造函數(shù)的第二個參數(shù)指定了解析器的類型,這里我們使用了Python內(nèi)置的html.parser解析器蝙眶。

接下來季希,我們調(diào)用了BeautifulSoup對象的prettify()方法,將解析后的HTML文檔格式化輸出幽纷。這個方法可以將HTML文檔按照標(biāo)準(zhǔn)的縮進(jìn)格式輸出式塌,方便我們查看和調(diào)試。

定位元素

在使用Beautiful Soup解析HTML文檔時友浸,我們通常需要定位文檔中的某些元素峰尝,然后提取它們的內(nèi)容或?qū)傩浴eautiful Soup提供了一些方便的方法來定位元素收恢,下面是一些常用的方法:

  • find()方法:查找文檔中第一個符合條件的元素武学。
  • find_all()方法:查找文檔中所有符合條件的元素,并返回一個列表伦意。
  • select()方法:使用CSS選擇器語法查找文檔中符合條件的元素火窒。

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

from bs4 import BeautifulSoup

html_doc = """
<html>
<head>
    <title>這是一個示例頁面</title>
</head>
<body>
    <h1>歡迎來到我的網(wǎng)站</h1>
    <p class="content">這是一個示例頁面驮肉,用于演示Beautiful Soup的使用方法熏矿。</p>
    <ul>
        <li><a >鏈接1</a></li>
        <li><a >鏈接2</a></li>
        <li><a >鏈接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循環(huán)將它們打印出來栏妖。最后,我們使用select()方法使用CSS選擇器語法查找了所有class為content的元素奖恰,并將其打印出來吊趾。

提取內(nèi)容和屬性

在定位到元素后宛裕,我們通常需要提取它們的內(nèi)容或?qū)傩浴eautiful Soup提供了一些方便的方法來實現(xiàn)這個功能论泛,下面是一些常用的方法:

  • text屬性:獲取元素的文本內(nèi)容揩尸。
  • string屬性:獲取元素的文本內(nèi)容,與text屬性類似屁奏,但是對于一些特殊的標(biāo)簽(如script岩榆、style等)會返回None。
  • get()方法:獲取元素的指定屬性值坟瓢。

下面是一個例子勇边,演示了如何使用這些方法來提取內(nèi)容和屬性:

from bs4 import BeautifulSoup

html_doc = """
<html>
<head>
    <title>這是一個示例頁面</title>
</head>
<body>
    <h1>歡迎來到我的網(wǎng)站</h1>
    <p class="content">這是一個示例頁面,用于演示Beautiful Soup的使用方法折联。</p>
    <ul>
        <li><a >鏈接1</a></li>
        <li><a >鏈接2</a></li>
        <li><a >鏈接3</a></li>
    </ul>
</body>
</html>
"""

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

# 獲取元素的文本內(nèi)容
title_text = soup.title.text
print(title_text)

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

在這個例子中粒褒,我們首先使用text屬性獲取了title元素的文本內(nèi)容,并將其打印出來诚镰。接下來奕坟,我們使用find()方法查找了第一個a元素,并使用get()方法獲取了它的href屬性值清笨,并將其打印出來月杉。

總結(jié)

Beautiful Soup是一個非常常用的Python庫,它可以幫助我們解析HTML和XML文檔抠艾,并提供了一些方便的方法來定位和提取數(shù)據(jù)苛萎。在使用Beautiful Soup時,我們通常需要使用find()跌帐、find_all()select()等方法來定位元素首懈,然后使用text、stringget()等方法來提取內(nèi)容和屬性谨敛。

2.基于bs4的環(huán)境搭建

在使用BeautifulSoup之前,需要先安裝bs4庫滤否×忱辏可以使用pip命令安裝:

pip install bs4

環(huán)境搭建完成后,可以進(jìn)行以下操作藐俺。

初始化BeautifulSoup對象

BeautifulSoup初始化時需要兩個參數(shù)炊甲,第一個參數(shù)是HTML或XML文檔的字符串,第二個參數(shù)是指定使用哪種解析器進(jìn)行解析欲芹。常用的解析器包括html.parser卿啡、lxmlhtml5lib,其中l(wèi)xml解析器解析速度較快菱父,而html5lib解析器則能夠處理一些語法非常松散的HTML文檔颈娜。

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

from bs4 import BeautifulSoup

html_doc = '''<html>
<head>
    <title>網(wǎng)頁標(biāo)題</title>
</head>
<body>
    <h1 class="title">網(wǎng)頁正文</h1>
    <div class="content">
        <p>第一段內(nèi)容</p>
        <p>第二段內(nèi)容</p>
        <p>第三段內(nèi)容</p>
        <ul>
            <li><a >鏈接一</a></li>
            <li><a >鏈接二</a></li>
            <li><a >鏈接三</a></li>
        </ul>
    </div>
</body>
</html>'''

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

查找元素

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

以下是根據(jù)標(biāo)簽和屬性查找元素的代碼:

# 查找所有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()方法可以獲取某個特定屬性值。

以下是根據(jù)屬性提取元素的代碼:

# 獲取所有a標(biāo)簽的href屬性
a_s = soup.find_all('a')
for a in a_s:
    print(a['href'])

# 獲取第一個a標(biāo)簽的href屬性
a = soup.find('a')
print(a.get('href'))

使用CSS選擇器

使用BeautifulSoupselect()方法可以通過CSS選擇器查找元素同仆。

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

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

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

BeautifulSoup提供了許多方法可以方便地操作HTML和XML文檔萤捆,具體使用可以參照官方文檔進(jìn)行。

3.bs4節(jié)點選擇器

在使用BeautifulSoup解析HTML代碼時俗批,通過節(jié)點選擇器可以選擇HTML文檔中的指定部分俗或,常用的節(jié)點選擇器包括標(biāo)簽選擇器、類選擇器岁忘、id選擇器蕴侣、屬性選擇器等。

標(biāo)簽選擇器

標(biāo)簽選擇器是最常用的選擇器臭觉,它根據(jù)HTML標(biāo)簽名稱來選擇HTML文檔中的元素昆雀。可以使用find()或find_all()方法來實現(xiàn)標(biāo)簽選擇器蝠筑。

# 選擇第一個p標(biāo)簽
soup.find('p')

# 選擇所有p標(biāo)簽
soup.find_all('p')

類選擇器

類選擇器是通過元素的class屬性進(jìn)行選擇狞膘,可以使用CSS選擇器語法來選擇單個或多個類。

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

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

id選擇器

id選擇器是根據(jù)id屬性進(jìn)行選擇什乙,可以使用CSS選擇器語法選擇具有指定id的元素挽封。可以使用find()方法來實現(xiàn)id選擇器臣镣。

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

屬性選擇器

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

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

子選擇器

子選擇器是通過選擇器名稱的空格分隔符來實現(xiàn)選擇父元素下的子元素点待。

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

后代選擇器

后代選擇器使用選擇器名稱的大于號>分隔符來實現(xiàn)選擇某個父元素下的直接子元素。

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

兄弟選擇器

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

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

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

以上就是使用BeautifulSoup的節(jié)點選擇器的常用方法苗踪,基于選擇器的使用,可以解析和提取HTML文檔中的各種元素和屬性信息削锰。

4.bs4屬性選擇器

在Beautiful Soup中通铲,我們可以使用屬性選擇器來選擇具有特定屬性的標(biāo)簽。屬性選擇器使用方括號[]來指定屬性名稱和屬性值器贩。

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

選擇具有特定屬性的標(biāo)簽

soup.select('tag[attr]')

例如颅夺,選擇所有具有class屬性的div標(biāo)簽:

soup.select('div[class]')

選擇具有特定屬性和屬性值的標(biāo)簽

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

例如朋截,選擇所有class屬性為"example"的div標(biāo)簽:

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

選擇具有特定屬性但不限制屬性值的標(biāo)簽

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

例如,選擇所有具有id屬性的標(biāo)簽:

soup.select('[id*]')

選擇具有特定屬性值的標(biāo)簽碗啄,但不限制屬性名稱

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

例如质和,選擇所有屬性值包含"example"的標(biāo)簽:

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

選擇具有多個屬性的標(biāo)簽

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

例如,選擇所有同時具有class屬性為"example"和id屬性為"test"的div標(biāo)簽:

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

5.bs4層級選擇器

BeautifulSoup庫提供了一些層級選擇器稚字,可以用于選擇HTML文檔中的指定層級元素饲宿。層級選擇器可以嵌套使用,以實現(xiàn)更精細(xì)的元素選擇胆描。

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

descendants選擇器

該選擇器用于選擇當(dāng)前元素的所有后代元素瘫想,包括子元素、子元素的子元素昌讲、子元素的子元素的子元素等国夜。使用descendants方法進(jìn)行查找,返回所有后代元素的生成器對象短绸。

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

children選擇器

該選擇器用于選擇當(dāng)前元素的所有子元素车吹,不包括子元素的子元素。使用children方法進(jìn)行查找醋闭,返回當(dāng)前元素的所有子元素的生成器對象窄驹。

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

parent選擇器

該選擇器用于選擇當(dāng)前元素的父元素,使用parent方法進(jìn)行查找证逻,返回當(dāng)前元素的父元素乐埠。

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

parents選擇器

該選擇器用于選擇當(dāng)前元素的所有祖先元素,返回一個生成器對象囚企。與descendants方法不同丈咐,該方法只返回直接祖先元素,不包括更遠(yuǎn)的祖先元素龙宏。

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

next_siblingprevious_sibling選擇器

next_sibling選擇器用于選擇當(dāng)前元素的下一個兄弟元素棵逊,previous_sibling選擇器用于選擇當(dāng)前元素的上一個兄弟元素。

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

以上就是bs4層級選擇器的常見方法烦衣,這些方法可以很好地幫助我們選擇HTML文檔中的特定元素來進(jìn)行后續(xù)的數(shù)據(jù)提取和處理歹河。

3.數(shù)據(jù)入庫

前言

數(shù)據(jù)入庫是指將采集好的數(shù)據(jù)存儲到數(shù)據(jù)庫中以便后續(xù)處理和分析。作為一名PC端爬蟲工程師花吟,掌握數(shù)據(jù)入庫技能是必不可少的。在進(jìn)行數(shù)據(jù)采集的同時厨姚,將數(shù)據(jù)實時地存儲到數(shù)據(jù)庫中衅澈,可以讓數(shù)據(jù)得到更好地管理和利用,提高效率和效益谬墙。

一般而言今布,進(jìn)行數(shù)據(jù)入庫有以下幾個步驟:

  • 數(shù)據(jù)庫的創(chuàng)建和配置:選擇一個合適的數(shù)據(jù)庫经备,根據(jù)實際需要創(chuàng)建數(shù)據(jù)庫表和配置數(shù)據(jù)庫連接等參數(shù)。

  • 數(shù)據(jù)庫連接:建立數(shù)據(jù)庫與Python的連接部默。有關(guān)Python連接數(shù)據(jù)庫的方法有很多種侵蒙,比如通過Python自帶的SQLite數(shù)據(jù)庫模塊、通過MySQL Connector等第三方庫進(jìn)行連接傅蹂。

  • 數(shù)據(jù)準(zhǔn)備和清洗:在進(jìn)行數(shù)據(jù)入庫之前纷闺,需要進(jìn)行針對性的數(shù)據(jù)準(zhǔn)備和清洗工作。比如份蝴,對采集到的數(shù)據(jù)進(jìn)行初步處理犁功,處理掉無意義的數(shù)據(jù),將有用的數(shù)據(jù)組織好婚夫。

  • 數(shù)據(jù)的插入和更新:通過Python提供的數(shù)據(jù)庫操作工具(如SQLAlchemy)或sql語句來進(jìn)行數(shù)據(jù)的插入和更新操作浸卦。

  • 數(shù)據(jù)庫的維護(hù):包括對數(shù)據(jù)庫表的清理、優(yōu)化和備份等操作案糙,以確保數(shù)據(jù)庫的穩(wěn)定運行限嫌。

需要注意的是,數(shù)據(jù)庫入庫不僅涉及到數(shù)據(jù)庫本身的知識时捌,還需要對Python編程語言有一定的掌握怒医。因此,PC端爬蟲工程師在進(jìn)行數(shù)據(jù)入庫之前匣椰,需要先掌握Python的基礎(chǔ)語法裆熙,熟練掌握Python的相關(guān)技巧,才能順利地進(jìn)行數(shù)據(jù)采集和入庫工作禽笑。

總而言之入录,數(shù)據(jù)入庫是PC端爬蟲工程師不可或缺的一項技能。只有掌握好數(shù)據(jù)入庫技能佳镜,才能為企業(yè)或個人實現(xiàn)更好地數(shù)據(jù)分析和應(yīng)用僚稿,提高數(shù)據(jù)價值。

一丶MySQL

MySQL是一種常用的關(guān)系型數(shù)據(jù)庫管理系統(tǒng)蟀伸,廣泛應(yīng)用于各種應(yīng)用場景蚀同。在進(jìn)行數(shù)據(jù)采集和入庫工作時,掌握MySQL數(shù)據(jù)庫的使用是極為重要的啊掏。

1.MySQL表結(jié)構(gòu)設(shè)計

MySQL表結(jié)構(gòu)設(shè)計是進(jìn)行數(shù)據(jù)入庫時需要考慮的一個重要問題蠢络。一個好的表結(jié)構(gòu)設(shè)計可以保證數(shù)據(jù)的存儲和管理更加高效和便捷。以下是幾個關(guān)鍵點迟蜜,供PC端爬蟲工程師在進(jìn)行MySQL表結(jié)構(gòu)設(shè)計時參考:

  • 字段設(shè)定:在表結(jié)構(gòu)設(shè)計中刹孔,需要設(shè)定字段和對應(yīng)的數(shù)據(jù)類型。字段的設(shè)定需考慮數(shù)據(jù)的類型娜睛、長度髓霞、是否允許為空卦睹、是否唯一、是否自增等因素方库。在設(shè)計字段時需遵循最小化原則结序,避免不必要的字段,以減輕數(shù)據(jù)庫處理壓力纵潦。

  • 主鍵徐鹤、唯一鍵、索引等設(shè)定:通過索引可以提高查詢的效率酪穿,因此在數(shù)據(jù)入庫時應(yīng)該考慮添加索引凳干。一般而言,需要給表中的字段設(shè)定主鍵被济、唯一鍵和普通索引等救赐,以優(yōu)化數(shù)據(jù)的查詢性能。

  • 表的級聯(lián)關(guān)系:在設(shè)計表結(jié)構(gòu)時只磷,需要考慮多表之間的關(guān)系经磅。比如,是采用多個獨立的表钮追,還是將其合并為一個復(fù)雜的表预厌。還需考慮多表之間的級聯(lián)關(guān)系,以確保數(shù)據(jù)的一致性元媚。

  • 設(shè)定數(shù)據(jù)表的字符集和排序規(guī)則:在MySQL表的結(jié)構(gòu)設(shè)計中轧叽,還需考慮字符集和排序規(guī)則的設(shè)定。要根據(jù)實際情況刊棕,選擇合適的字符集和排序規(guī)則炭晒,以避免數(shù)據(jù)存儲時出現(xiàn)亂碼或者排序問題。

2.MySQL數(shù)據(jù)寫入規(guī)范

MySQL數(shù)據(jù)寫入規(guī)范是進(jìn)行數(shù)據(jù)入庫時需要考慮的一個重要問題甥角。一個良好的數(shù)據(jù)寫入規(guī)范可以保證數(shù)據(jù)的準(zhǔn)確性和一致性网严,確保數(shù)據(jù)在數(shù)據(jù)庫中的正確存儲。以下是PC端爬蟲工程師需要遵循的MySQL數(shù)據(jù)寫入規(guī)范:

  • 字段值格式與表結(jié)構(gòu)匹配:在進(jìn)行數(shù)據(jù)寫入時嗤无,需要確保字段值的格式與表結(jié)構(gòu)匹配妄呕。即使數(shù)據(jù)庫允許數(shù)據(jù)隨意寫入坦报,也應(yīng)該遵循表結(jié)構(gòu)設(shè)計的原則砖织,將數(shù)據(jù)寫入到正確的字段中瑟捣。

  • 數(shù)據(jù)的完整性:在進(jìn)行數(shù)據(jù)寫入時,需要確保數(shù)據(jù)的完整性嚎卫。應(yīng)盡量避免數(shù)據(jù)缺失肝断、重復(fù)或者錯誤等問題,以免對后續(xù)分析和應(yīng)用造成影響驰凛。

  • 數(shù)據(jù)的規(guī)范化:對于涉及字符串胸懈、日期等數(shù)據(jù)類型的字段,需要考慮到數(shù)據(jù)的規(guī)范化恰响。比如趣钱,對于日期數(shù)據(jù),應(yīng)統(tǒng)一使用一種日期格式胚宦,并避免使用默認(rèn)格式等導(dǎo)致的問題首有。

  • 事務(wù)管理:在進(jìn)行數(shù)據(jù)寫入時,應(yīng)盡量使用事務(wù)來確保數(shù)據(jù)的一致性枢劝。比如井联,在寫入多條記錄時,可以將它們一起寫入到數(shù)據(jù)庫中您旁,并在最后再統(tǒng)一提交烙常,以確保數(shù)據(jù)在寫入的過程中保持一致性。

  • 避免超限數(shù)據(jù)的寫入:在進(jìn)行數(shù)據(jù)寫入時鹤盒,應(yīng)嚴(yán)格避免超限數(shù)據(jù)的寫入蚕脏,例如數(shù)據(jù)長度超出字段長度等問題。如果數(shù)據(jù)超限侦锯,會導(dǎo)致數(shù)據(jù)丟失或者數(shù)據(jù)庫撐爆等問題驼鞭。

3.MySQL動態(tài)傳參

MySQL動態(tài)傳參是進(jìn)行數(shù)據(jù)入庫時經(jīng)常用到的一種技巧。通過動態(tài)傳參尺碰,可以有效地提高M(jìn)ySQL數(shù)據(jù)庫寫入的效率挣棕,減少程序代碼的冗余,優(yōu)化數(shù)據(jù)入庫過程亲桥。以下是幾種常用的MySQL動態(tài)傳參方式:

使用Python的字符串格式化方法進(jìn)行動態(tài)傳參:可以使用Python的字符串的format方法進(jìn)行MySQL參數(shù)的傳遞洛心。在進(jìn)行數(shù)據(jù)寫入操作時,可以將MySQL語句和Python字典或元組進(jìn)行結(jié)合两曼,實現(xiàn)動態(tài)傳參的效果皂甘。例如:

import MySQLdb

# 定義數(shù)據(jù)表名
table_name = "student"

# 定義學(xué)生信息
student_info = {
    "name": "Tom",
    "age": 18,
    "grade": "A"
}

# 動態(tài)傳參
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']
)

# 連接數(shù)據(jù)庫
conn = MySQLdb.connect('localhost', 'username', 'password', 'database_name')
# 獲取游標(biāo)對象
cursor = conn.cursor()
# 執(zhí)行操作
cursor.execute(sql)
# 提交事務(wù)
conn.commit()
# 關(guān)閉游標(biāo)和連接
cursor.close()
conn.close()

使用MySQLdb模塊的execute方法進(jìn)行動態(tài)傳參:使用MySQLdb的execute方法進(jìn)行動態(tài)傳參,只需要在SQL語句中使用占位符%s悼凑,然后在執(zhí)行execute方法時傳遞參數(shù)列表即可偿枕。例如:

import MySQLdb

# 定義數(shù)據(jù)表名
table_name = "student"

# 定義學(xué)生信息
student_info = {
    "name": "Tom",
    "age": 18,
    "grade": "A"
}

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

# 連接數(shù)據(jù)庫
conn = MySQLdb.connect('localhost', 'username', 'password', 'database_name')
# 獲取游標(biāo)對象
cursor = conn.cursor()
# 執(zhí)行操作
cursor.execute(sql, (student_info['name'], student_info['age'], student_info['grade']))
# 提交事務(wù)
conn.commit()
# 關(guān)閉游標(biāo)和連接
cursor.close()
conn.close()

總之,MySQL動態(tài)傳參是進(jìn)行數(shù)據(jù)入庫時經(jīng)常使用的一種技巧户辫。PC端爬蟲工程師掌握MySQL動態(tài)傳參的使用方法渐夸,可以對SQL語句進(jìn)行動態(tài)的參數(shù)傳遞,從而提高數(shù)據(jù)庫寫入的效率渔欢、減少代碼冗余墓塌。在進(jìn)行數(shù)據(jù)入庫時,建議使用MySQL動態(tài)傳參技巧,以提高數(shù)據(jù)的寫入效率和準(zhǔn)確性苫幢。

4.MySQL對接爬蟲實戰(zhàn)

在進(jìn)行爬蟲數(shù)據(jù)采集和入庫時访诱,MySQL是一個常用的關(guān)系型數(shù)據(jù)庫管理系統(tǒng),其穩(wěn)定性和可靠性被廣泛認(rèn)可韩肝。以下是PC端爬蟲工程師可以按照的步驟触菜,將爬蟲采集數(shù)據(jù)寫入到MySQL數(shù)據(jù)庫中:

  • 創(chuàng)建MySQL數(shù)據(jù)庫表結(jié)構(gòu):在MySQL數(shù)據(jù)庫中創(chuàng)建一個數(shù)據(jù)表,該表的表結(jié)構(gòu)應(yīng)根據(jù)數(shù)據(jù)的類型和存儲需求進(jìn)行設(shè)計哀峻。在表結(jié)構(gòu)設(shè)計時需要考慮字段設(shè)定涡相、主鍵、唯一鍵剩蟀、索引等因素催蝗。

  • 使用Python中的爬蟲框架進(jìn)行數(shù)據(jù)采集:使用Python中的Scrapy或者BeautifulSoup等常用的PC端爬蟲框架進(jìn)行數(shù)據(jù)采集,將采集到的數(shù)據(jù)存儲在Python的變量中育特。

  • 連接MySQL數(shù)據(jù)庫:使用Python的MySQLdb或pymysql等第三方庫連接MySQL數(shù)據(jù)庫丙号,并進(jìn)行相應(yīng)的參數(shù)配置。

  • 實現(xiàn)數(shù)據(jù)寫入操作:使用Python的cursor對象且预,通過sql語句將數(shù)據(jù)插入到MySQL數(shù)據(jù)庫中槽袄。在插入數(shù)據(jù)時,需要遵循MySQL數(shù)據(jù)庫的數(shù)據(jù)寫入規(guī)范锋谐,保證數(shù)據(jù)的完整性遍尺、一致性和安全性。如果需要動態(tài)傳參涮拗,在插入數(shù)據(jù)時還需要用到字符串格式化方法或者M(jìn)ySQLdb的execute方法進(jìn)行動態(tài)傳參乾戏。

  • 關(guān)閉數(shù)據(jù)庫連接:當(dāng)完成數(shù)據(jù)入庫操作后,應(yīng)及時關(guān)閉數(shù)據(jù)庫連接三热,以釋放資源鼓择。

下面是一個將采集到的數(shù)據(jù)寫入MySQL數(shù)據(jù)庫的示例代碼:

import MySQLdb

# 連接MySQL數(shù)據(jù)庫
conn = MySQLdb.connect('localhost', 'username', 'password', 'database_name')

# 獲取游標(biāo)對象
cursor = conn.cursor()

# 采集到的數(shù)據(jù)
book = {'name': 'Python入門精通', 'author': '張三', 'price': 28}

# 數(shù)據(jù)庫寫入操作
sql = "INSERT INTO books (name, author, price) VALUES ('%s', '%s', %f)" % (book['name'], book['author'], book['price'])
try:
    # 執(zhí)行SQL語句
    cursor.execute(sql)
    # 提交事務(wù)
    conn.commit()
except Exception as e:
    # 發(fā)生異常時回滾
    print(str(e))
    conn.rollback()

# 關(guān)閉游標(biāo)和連接
cursor.close()
conn.close()

將爬蟲采集的數(shù)據(jù)寫入MySQL數(shù)據(jù)庫是PC端爬蟲工程師需要掌握的重要技能之一。需要合理設(shè)計數(shù)據(jù)表結(jié)構(gòu)就漾,使用Python的爬蟲框架進(jìn)行數(shù)據(jù)采集呐能,正確連接MySQL數(shù)據(jù)庫,遵循MySQL的數(shù)據(jù)寫入規(guī)范進(jìn)行數(shù)據(jù)寫入操作抑堡,并嚴(yán)格保障數(shù)據(jù)的完整性和一致性摆出。

二丶MongoDB

除了關(guān)系型數(shù)據(jù)庫MySQL,另一種非常流行的數(shù)據(jù)庫是NoSQL數(shù)據(jù)庫MongoDB首妖。相比于MySQL偎漫,MongoDB具備更好的可擴展性和更方便的數(shù)據(jù)處理方式,是現(xiàn)代Web應(yīng)用程序的熱門選擇有缆。以下是將爬蟲采集數(shù)據(jù)寫入MongoDB數(shù)據(jù)庫的步驟:

  • 安裝MongoDB數(shù)據(jù)庫:在開始使用MongoDB數(shù)據(jù)庫之前象踊,需要安裝MongoDB以及相應(yīng)的Python驅(qū)動程序pymongo温亲。MongoDB官網(wǎng)提供了各種安裝方式和文檔。

  • 連接MongoDB數(shù)據(jù)庫:使用pymongo庫連接MongoDB數(shù)據(jù)庫杯矩,并進(jìn)行相應(yīng)的參數(shù)配置栈虚。MongoDB需要指定數(shù)據(jù)庫所在服務(wù)器地址、端口號菊碟、數(shù)據(jù)庫名稱等連接信息节芥。

  • 創(chuàng)建MongoDB數(shù)據(jù)庫和集合:MongoDB是面向文檔的數(shù)據(jù)庫,不需要像MySQL一樣設(shè)計表結(jié)構(gòu)逆害,而是直接存儲JSON格式的文檔◎纪眨可以首先創(chuàng)建MongoDB數(shù)據(jù)庫和集合魄幕,然后在代碼中直接插入文檔。使用pymongo庫提供的MongoClient對象可以連接MongoDB數(shù)據(jù)庫颖杏,并使用相應(yīng)的方法創(chuàng)建數(shù)據(jù)庫和集合等纯陨。

  • 實現(xiàn)數(shù)據(jù)寫入操作:使用pymongo庫提供的insert_oneinsert_many等方法將Python變量中的數(shù)據(jù)插入到MongoDB中。在插入數(shù)據(jù)時留储,需要遵循MongoDB的數(shù)據(jù)寫入規(guī)范翼抠,保證數(shù)據(jù)的完整性、一致性和安全性获讳。如果需要動態(tài)傳參阴颖,在插入數(shù)據(jù)時還需要用到Python格式化字符串或bson模塊的tobson方法。

  • 關(guān)閉數(shù)據(jù)庫連接:當(dāng)完成數(shù)據(jù)入庫操作后丐膝,應(yīng)及時關(guān)閉數(shù)據(jù)庫連接量愧,以釋放資源。

下面是一個將采集到的數(shù)據(jù)寫入MongoDB數(shù)據(jù)庫的示例代碼:

import pymongo
import json

# 連接MongoDB數(shù)據(jù)庫
client = pymongo.MongoClient(host='localhost', port=27017)

# 創(chuàng)建MongoDB數(shù)據(jù)庫和集合
db = client['bookstore']
collection = db['books']

# 采集到的數(shù)據(jù)
book = {'name': 'Python入門精通', 'author': '張三', 'price': 28}

# 數(shù)據(jù)庫寫入操作
try:
    # 將Python字典轉(zhuǎn)換為MongoDB的文檔格式
    doc = json.loads(json.dumps(book))
    # 插入文檔到MongoDB
    collection.insert_one(doc)
except Exception as e:
    print(str(e))

# 關(guān)閉MongoDB連接
client.close()

將爬蟲采集的數(shù)據(jù)寫入MongoDB數(shù)據(jù)庫是PC端爬蟲工程師需要掌握的另一個重要技能帅矗。需要首先安裝MongoDB數(shù)據(jù)庫和Python驅(qū)動程序pymongo偎肃,然后使用pymongo庫連接MongoDB數(shù)據(jù)庫,創(chuàng)建數(shù)據(jù)庫和集合浑此,使用insert_oneinsert_many等方法將數(shù)據(jù)插入到MongoDB中累颂。同時也需要遵循MongoDB的數(shù)據(jù)寫入規(guī)范,保障數(shù)據(jù)的完整性和一致性凛俱。

1.MongoDB數(shù)據(jù)寫入規(guī)范

MongoDB是一種非關(guān)系型數(shù)據(jù)庫紊馏,相對于傳統(tǒng)關(guān)系型數(shù)據(jù)庫MySQL,它有許多的特性和優(yōu)勢最冰,但是在使用時需要遵守一定的數(shù)據(jù)寫入規(guī)范瘦棋,以保證數(shù)據(jù)的安全性和一致性。下面是在將數(shù)據(jù)寫入MongoDB時需要遵守的規(guī)范:

  • 字段命名規(guī)范:MongoDB支持使用Unicode字符集中的所有字符作為字段名稱暖哨,但是不推薦使用除字母數(shù)字和下劃線以外的特殊字符赌朋,且建議使用小寫字母凰狞。字段名稱不能為空字符串,并且不能以$開頭沛慢。

  • 數(shù)據(jù)格式規(guī)范:在將數(shù)據(jù)寫入MongoDB中時赡若,需要保證文檔中每個字段的數(shù)據(jù)類型和數(shù)據(jù)格式的一致性。如果想要將Python中的數(shù)據(jù)寫入MongoDB团甲,可以先將Python中的數(shù)據(jù)格式化為JSON字符串或字典逾冬,然后再將其轉(zhuǎn)換為MongoDB文檔格式。

  • 文檔唯一性規(guī)范:MongoDB中的每個文檔都應(yīng)該具有唯一的_id字段躺苦。如果在寫入文檔時沒有指定_id字段身腻,則MongoDB會為每個文檔自動生成一個ObjectId類型的_id字段。

  • 數(shù)據(jù)寫入確認(rèn)規(guī)范:當(dāng)使用MongoDB寫入數(shù)據(jù)時匹厘,應(yīng)該使用寫入確認(rèn)來確保數(shù)據(jù)已經(jīng)成功寫入數(shù)據(jù)庫嘀趟。MongoDB提供了四種寫入確認(rèn)級別,分別為:未確認(rèn)寫入愈诚、確認(rèn)主節(jié)點寫入她按、確認(rèn)大多數(shù)節(jié)點寫入和確認(rèn)所有節(jié)點寫入。

  • 數(shù)據(jù)更新規(guī)范:在更新MongoDB中的文檔時炕柔,可以使用update方法進(jìn)行更新酌泰。使用update方法時,需要指定更新的文檔匕累、更新的方式和更新的條件陵刹。如果不指定更新條件,則默認(rèn)會更新所有符合條件的文檔哩罪。更新操作還可以將某個字段的值進(jìn)行遞增或遞減操作授霸。

  • 數(shù)據(jù)刪除規(guī)范:在MongoDB中刪除文檔時,可以使用remove方法進(jìn)行刪除际插。使用remove方法時碘耳,需要指定刪除的文檔和刪除的條件。如果不指定條件框弛,則默認(rèn)會刪除所有文檔辛辨。

在將數(shù)據(jù)寫入MongoDB中時,需要遵守一定的規(guī)范瑟枫,以保證數(shù)據(jù)的安全性和一致性斗搞。需要注意字段命名規(guī)范、數(shù)據(jù)格式規(guī)范慷妙、文檔唯一性規(guī)范僻焚、數(shù)據(jù)寫入確認(rèn)規(guī)范、數(shù)據(jù)更新規(guī)范和數(shù)據(jù)刪除規(guī)范膝擂。

2.MongoDB數(shù)據(jù)異常處理

在進(jìn)行數(shù)據(jù)入庫到MongoDB的過程中虑啤,可能會遇到一些異常情況隙弛,例如寫入數(shù)據(jù)失敗、查詢數(shù)據(jù)出錯等等狞山。為了保證數(shù)據(jù)的完整性和正確性全闷,需要進(jìn)行一些異常處理。

以下是在使用MongoDB進(jìn)行數(shù)據(jù)入庫時萍启,可能會遇到的異常情況及相應(yīng)的處理方法:

  • 寫入數(shù)據(jù)失敗:在將數(shù)據(jù)寫入MongoDB的過程中总珠,可能會由于網(wǎng)絡(luò)問題、數(shù)據(jù)庫連接失敗或者其他原因?qū)е聦懭胧】贝俊4藭r局服,需要進(jìn)行重試操作,并且可以使用MongoDB提供的異常處理機制來捕獲異常屡律,并進(jìn)行相應(yīng)的處理腌逢。

  • 查詢數(shù)據(jù)出錯:在查詢MongoDB中的文檔時,可能會由于查詢條件錯誤超埋、查詢字段不存在或其他原因?qū)е虏樵兂鲥e。此時佳鳖,可以使用MongoDB提供的異常處理機制來捕獲異常霍殴,并進(jìn)行相應(yīng)的處理。

  • 數(shù)據(jù)庫連接失敗:在連接MongoDB數(shù)據(jù)庫時系吩,可能會由于網(wǎng)絡(luò)問題来庭、數(shù)據(jù)庫服務(wù)未啟動或其他原因?qū)е逻B接失敗。此時穿挨,需要檢查數(shù)據(jù)庫服務(wù)是否正常運行月弛,并重新連接數(shù)據(jù)庫。

  • 數(shù)據(jù)庫連接斷開:在MongoDB與客戶端進(jìn)行通信時科盛,可能會由于網(wǎng)絡(luò)問題或者其他原因?qū)е逻B接斷開帽衙。此時,需要重新連接MongoDB數(shù)據(jù)庫贞绵,并處理異常情況厉萝。

  • 數(shù)據(jù)庫寫鎖:在進(jìn)行寫入操作時,可能會由于另一個線程正在寫入同一個文檔而出現(xiàn)寫入鎖榨崩。此時谴垫,需要等待寫入鎖釋放,然后再進(jìn)行操作母蛛。

  • 數(shù)據(jù)庫讀鎖:在進(jìn)行讀取操作時翩剪,可能會由于另一個線程正在更新同一個文檔而出現(xiàn)讀取鎖。此時彩郊,可以選擇等待讀取鎖釋放前弯,或者強制獲取讀取鎖進(jìn)行讀取操作蚪缀。

在進(jìn)行數(shù)據(jù)入庫到MongoDB的過程中,可能會遇到各種異常情況博杖,需要注意異常處理椿胯,以保證數(shù)據(jù)的完整性和正確性。需要使用MongoDB提供的異常處理機制剃根,對可能出現(xiàn)的異常進(jìn)行捕獲哩盲,并進(jìn)行相應(yīng)的處理。此外狈醉,還需要注意在進(jìn)行寫入操作時可能出現(xiàn)的寫鎖廉油,以及在進(jìn)行讀取操作時可能出現(xiàn)的讀鎖。

3.爬蟲對接MongoDB實戰(zhàn)操作

在進(jìn)行爬蟲數(shù)據(jù)采集時苗傅,將采集到的數(shù)據(jù)存儲到MongoDB數(shù)據(jù)庫中是一個比較常見的操作抒线。下面簡單介紹一下如何使用Python爬蟲程序?qū)覯ongoDB數(shù)據(jù)庫進(jìn)行實戰(zhàn)操作。

  • 安裝MongoDB驅(qū)動程序:Python爬蟲程序可以使用第三方庫–pymongo–來操作MongoDB數(shù)據(jù)庫渣慕。首先需要安裝pymongo庫嘶炭,可以使用pip命令進(jìn)行安裝:
pip install pymongo
  • 連接MongoDB數(shù)據(jù)庫:使用pymongo庫連接MongoDB數(shù)據(jù)庫非常簡單。需要指定MongoDB服務(wù)器的IP地址及端口號逊桦,同時指定要使用的數(shù)據(jù)庫名稱和集合名稱眨猎。示例代碼如下:
import pymongo

# 連接MongoDB服務(wù)器
client = pymongo.MongoClient("mongodb://localhost:27017/")

# 選擇數(shù)據(jù)庫和集合
db = client["testdb"]
col = db["testcol"]

在實際操作中,可以根據(jù)需要自己定義數(shù)據(jù)庫和集合的名稱强经。

  • 插入數(shù)據(jù)到MongoDB:將爬蟲采集到的數(shù)據(jù)插入到MongoDB中睡陪,需要使用pymongo庫提供的insert_one()insert_many()方法。如果要插入多條數(shù)據(jù)匿情,可以使用insert_many()方法兰迫。示例代碼如下:
import pymongo

# 連接MongoDB服務(wù)器
client = pymongo.MongoClient("mongodb://localhost:27017/")

# 選擇數(shù)據(jù)庫和集合
db = client["testdb"]
col = db["testcol"]

# 插入一條數(shù)據(jù)
data = {"title": "Python編程", "price": 88.8}
col.insert_one(data)

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

# 連接MongoDB服務(wù)器
client = pymongo.MongoClient("mongodb://localhost:27017/")

# 選擇數(shù)據(jù)庫和集合
db = client["testdb"]
col = db["testcol"]

# 查詢數(shù)據(jù)
data = col.find_one({"title": "Python編程"})
print(data)

for data in col.find():
    print(data)
  • 更新數(shù)據(jù)和刪除數(shù)據(jù):使用pymongo庫提供的update_one()转砖、update_many()须鼎、delete_one()delete_many()方法可以更新和刪除MongoDB數(shù)據(jù)庫中的數(shù)據(jù)。
import pymongo

# 連接MongoDB服務(wù)器
client = pymongo.MongoClient("mongodb://localhost:27017/")

# 選擇數(shù)據(jù)庫和集合
db = client["testdb"]
col = db["testcol"]

# 更新數(shù)據(jù)
query = {"title": "Python編程"}
new_data = {"$set": {"price": 99.99}}
result = col.update_one(query, new_data)
print(result.modified_count)

# 刪除數(shù)據(jù)
query = {"title": "Python編程"}
result = col.delete_one(query)
print(result.deleted_count)

以上就是對接MongoDB數(shù)據(jù)庫的實戰(zhàn)操作府蔗。需要注意的是晋控,MongoDB數(shù)據(jù)庫在進(jìn)行大量寫入數(shù)據(jù)時,可能會遇到性能瓶頸問題姓赤,可以通過使用分片和索引等技術(shù)來提高M(jìn)ongoDB數(shù)據(jù)庫的性能赡译。

三丶JSON

進(jìn)行數(shù)據(jù)采集時,一種常見的數(shù)據(jù)存儲格式是JSON(JavaScript Object Notation)不铆。JSON格式具有輕量級蝌焚、結(jié)構(gòu)化等優(yōu)點裹唆,且易于使用和解析。下面介紹PC端爬蟲工程師采集數(shù)據(jù)后如何將數(shù)據(jù)存儲為JSON格式只洒。

使用Python標(biāo)準(zhǔn)庫json將數(shù)據(jù)轉(zhuǎn)換為JSON格式

Python標(biāo)準(zhǔn)庫json提供了loads(),load(),dumps()dump()四個函數(shù)用于JSON數(shù)據(jù)的解析和編碼许帐。其中,dump()函數(shù)可以將Python對象直接序列化為JSON文件毕谴,如下使用示例:

import json

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

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

使用Python第三方庫pandas將數(shù)據(jù)存儲為JSON格式

pandas是一種基于NumPy的數(shù)據(jù)分析工具成畦,支持多種數(shù)據(jù)格式的解析、操作和存儲涝开,其中就包括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將數(shù)據(jù)存儲為JSON格式

scrapy是一種廣泛應(yīng)用于Web爬蟲數(shù)據(jù)采集的Python框架,它默認(rèn)支持多種數(shù)據(jù)存儲方式银舱,包括JSON格式瘪匿。在使用scrapy框架進(jìn)行數(shù)據(jù)采集時,可以將數(shù)據(jù)存儲為JSON格式寻馏,示例代碼如下:

import scrapy

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

    def parse(self, response):
        # 爬蟲采集到的數(shù)據(jù)
        data = {
            "name": "Tom",
            "age": 18,
            "gender": "male"
        }

        # 將數(shù)據(jù)存儲為JSON格式
        yield data

進(jìn)行數(shù)據(jù)采集時柿顶,可以選擇將采集到的數(shù)據(jù)存儲為JSON格式〔偃恚可以使用Python標(biāo)準(zhǔn)庫json、第三方庫pandas或爬蟲框架scrapy提供的方法將數(shù)據(jù)以JSON格式存儲起來宪祥,以達(dá)到方便解析和處理的效果聂薪。

1.JSON對象和數(shù)組

JSON對象

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

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

其中耀找,name翔悠、age、gender是屬性野芒,對應(yīng)的值分別是Tom蓄愁、18、male狞悲;hobbies是一個數(shù)組撮抓,包含兩個元素reading和traveling。

JSON數(shù)組

JSON數(shù)組是由方括號“[]”包圍的一組值摇锋,不同值之間使用逗號“,”分隔丹拯。一個JSON數(shù)組可以包含零到多個值站超,示例如下:

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

這是一個包含三個JSON對象的數(shù)組默色,每個對象都包括name瓶蚂、age、gender三個屬性扁藕,分別表示姓名咬像、年齡算撮、性別。

使用JSON對象和JSON數(shù)組可以靈活地組織和存儲數(shù)據(jù)施掏。在進(jìn)行數(shù)據(jù)采集和數(shù)據(jù)處理時钮惠,PC端爬蟲工程師需要了解和掌握這兩種JSON結(jié)構(gòu)的相關(guān)知識,以便更好地將采集到的數(shù)據(jù)存儲為JSON格式七芭,進(jìn)行數(shù)據(jù)解析和處理等操作素挽。

2.JSON數(shù)據(jù)編碼

進(jìn)行數(shù)據(jù)采集和數(shù)據(jù)存儲時,需要將采集到的數(shù)據(jù)編碼為JSON格式狸驳,以便后續(xù)進(jìn)行解析和處理等操作预明。在Python語言中,使用json模塊可以方便地進(jìn)行JSON數(shù)據(jù)編碼耙箍。

具體操作如下:

導(dǎo)入json模塊

import json

將Python數(shù)據(jù)類型轉(zhuǎn)換為JSON格式

使用json.dump()方法撰糠,將Python數(shù)據(jù)類型(如字典、列表)轉(zhuǎn)換為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)

其中,參數(shù)obj為Python數(shù)據(jù)類型汁针,參數(shù)f為文件路徑术辐。

代碼示例:

import json

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

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

運行代碼后,會在當(dāng)前工作目錄中生成一個data.json文件施无,文件內(nèi)容為轉(zhuǎn)換后的JSON格式數(shù)據(jù):

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

將Python數(shù)據(jù)類型轉(zhuǎn)換為JSON格式辉词,返回JSON字符串

使用json.dumps()方法,將Python數(shù)據(jù)類型(如字典猾骡、列表)轉(zhuǎn)換為JSON格式瑞躺,并返回一個對應(yīng)的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)

其中兴想,參數(shù)obj為Python數(shù)據(jù)類型幢哨。

代碼示例:

import json

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

json_str = json.dumps(data)

print(json_str)

運行代碼后,控制臺會輸出轉(zhuǎn)換后的JSON格式字符串:

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

可以根據(jù)實際情況選擇使用json.dump()json.dumps()進(jìn)行JSON數(shù)據(jù)編碼襟企,以便將采集到的數(shù)據(jù)存儲為JSON格式嘱么,方便后續(xù)的數(shù)據(jù)處理和解析等操作。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市曼振,隨后出現(xiàn)的幾起案子几迄,更是在濱河造成了極大的恐慌,老刑警劉巖冰评,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件映胁,死亡現(xiàn)場離奇詭異,居然都是意外死亡甲雅,警方通過查閱死者的電腦和手機解孙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來抛人,“玉大人弛姜,你說我怎么就攤上這事⊙叮” “怎么了廷臼?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長绝页。 經(jīng)常有香客問我荠商,道長,這世上最難降的妖魔是什么续誉? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任莱没,我火速辦了婚禮,結(jié)果婚禮上酷鸦,老公的妹妹穿的比我還像新娘饰躲。我一直安慰自己,他們只是感情好臼隔,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布属铁。 她就那樣靜靜地躺著,像睡著了一般躬翁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上盯拱,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天盒发,我揣著相機與錄音,去河邊找鬼狡逢。 笑死宁舰,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的奢浑。 我是一名探鬼主播蛮艰,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼雀彼!你這毒婦竟也來了壤蚜?” 一聲冷哼從身側(cè)響起即寡,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎袜刷,沒想到半個月后聪富,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡著蟹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年墩蔓,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片萧豆。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡奸披,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出涮雷,到底是詐尸還是另有隱情阵面,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布份殿,位于F島的核電站膜钓,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏卿嘲。R本人自食惡果不足惜颂斜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拾枣。 院中可真熱鬧沃疮,春花似錦、人聲如沸梅肤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽姨蝴。三九已至俊啼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間左医,已是汗流浹背授帕。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留浮梢,地道東北人跛十。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像秕硝,于是被迫代替她去往敵國和親芥映。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容