从零开始学python(十二)如何成为一名优秀的爬虫工程师

前言

回顾之前讲述了python语法编程 必修入门基础和网络编程,多线程/多进程/协程等方面的内容,后续讲到了数据库编程篇MySQL,Redis,MongoDB篇,和机器学习,全栈开发,数据分析前面没看的也不用往前翻,系列文已经整理好了:


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到高级进阶路线图

一丶采集功底专题

1.网络请求

网络请求是爬虫工程师采集数据的重要手段之一。在PC端爬虫中,网络请求通常使用HTTP协议进行通信,通过发送HTTP请求获取目标网站的数据。

爬虫工程师需要掌握HTTP协议的基本知识,包括HTTP请求和响应的格式、常见的HTTP请求方法(如GET、POST等)、HTTP请求头和响应头的常见字段等。

在进行网络请求时,爬虫工程师通常使用HTTP客户端库,如Python中的requests库、Java中的HttpClient等。这些库封装了HTTP协议的细节,提供了简单易用的API,方便爬虫工程师进行网络请求。

爬虫工程师还需要了解一些反爬虫技术,如User-Agent伪装、IP代理等,以应对目标网站的反爬虫策略。

一丶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-Typeapplication/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-Typeapplication/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.分组

分组是指将正则表达式中的一部分用括号括起来,形成一个子表达式。分组可以用来限定匹配范围、提取匹配结果等。

例如,正则表达式<a href="(.?)">(.?)</a>中,用括号括起来的部分就是分组,第一个分组(.?)用来匹配链接地址,第二个分组(.?)用来匹配链接文本。

2.通用匹配

通用匹配是指用.来匹配任意字符的正则表达式。通用匹配可以用来匹配一些不确定的字符,例如空格、换行符等。

例如,正则表达式<a href=".?">.?</a>中,用.来匹配链接地址和链接文本中间的任意字符,这样就可以匹配包含任意字符的链接了。

需要注意的是,通用匹配可能会匹配到一些不需要的字符,因此在使用时需要谨慎。

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 john@example.com.'
emails = re.findall(r'\b\w+@\w+\.\w+\b', text)
print(emails)

输出结果为:

['john@example.com']

match方法

match方法只能在字符串的开头匹配正则表达式,如果匹配成功,则返回一个匹配对象,否则返回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')

输出结果为:

No match

因为正则表达式\b\w+@\w+.\w+\b只能匹配单词边界处的邮箱地址,而字符串的开头不是单词边界。

search方法

search方法可以在字符串中查找第一个匹配正则表达式的子串,并返回一个匹配对象,否则返回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')

输出结果为:

john@example.com

因为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文档中的元素,如<div>、<p>等。
  • 属性节点(Attribute Node):表示XML或HTML文档中的属性,如class、id等。
  • 文本节点(Text Node):表示XML或HTML文档中的文本内容,如<div>hello world</div>中的hello world。

在XPath中,可以使用不同的语法来选择DOM节点,常见的语法包括:

  • 路径表达式(Path Expression):使用路径表达式可以选择文档中的某个节点或一组节点。例如,选择所有的<div>元素可以使用路径表达式//div。
  • 轴(Axis):轴是一种用于选择节点的方法,可以选择与当前节点有特定关系的节点。例如,选择当前节点的所有子节点可以使用轴child::。
  • 谓语(Predicate):谓语是一种用于过滤节点的方法,可以根据节点的属性或位置等信息来选择节点。例如,选择第一个<div>元素可以使用路径表达式(//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()'))

这样就可以将文章的信息提取出来,其中titleauthorpublish_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、stringget()等方法来提取内容和属性。

2.基于bs4的环境搭建

在使用BeautifulSoup之前,需要先安装bs4库。可以使用pip命令安装:

pip install bs4

环境搭建完成后,可以进行以下操作。

初始化BeautifulSoup对象

BeautifulSoup初始化时需要两个参数,第一个参数是HTML或XML文档的字符串,第二个参数是指定使用哪种解析器进行解析。常用的解析器包括html.parserlxmlhtml5lib,其中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选择器

使用BeautifulSoupselect()方法可以通过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_siblingprevious_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端爬虫工程师不可或缺的一项技能。只有掌握好数据入库技能,才能为企业或个人实现更好地数据分析和应用,提高数据价值。

一丶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_oneinsert_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_oneinsert_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格式,方便后续的数据处理和解析等操作。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容