本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:网络爬虫是自动化获取互联网数据的常用技术,本项目使用Python的requests库从京东网站抓取商品详情和用户评论。内容涵盖requests库的使用、爬虫基本原理、HTML和JSON数据解析、异常处理、分页处理、防封IP策略、数据存储方法,以及合法道德爬虫的重要性。学习此项目有助于掌握网络爬虫技术并为数据分析打基础。
京东商品和评论爬虫requests(代码可用)

1. Python requests库的使用

Python的 requests 库是网络编程中的一个重要工具,它通过简单易懂的API使得发送网络请求变得容易。 requests 库支持多种网络协议,比如HTTP、HTTPS,并且能够处理各种HTTP认证、代理以及会话保持等功能。它还在内部做了很多优化,如连接池管理、证书验证等,这使得 requests 库在效率和易用性上都非常出色。

本章将会深入探讨 requests 库的安装、基本使用方法以及如何使用它来处理网络请求和响应。我们将通过示例代码来展示如何使用 requests 发送GET和POST请求,以及如何处理JSON格式的响应数据。此外,还会介绍异常处理和HTTP头部信息的配置。

# 发送GET请求的示例代码
import requests

response = requests.get('https://api.example.com/data')
print(response.text)  # 打印响应的文本内容
print(response.json())  # 将响应文本解析为JSON格式

以上代码演示了如何使用 requests 库发送一个GET请求,并打印出服务器返回的原始文本和JSON格式的解析结果。这只是 requests 库强大功能的一个简单展示,接下来的章节将会介绍更多高级功能和技巧。

2. 网络爬虫工作原理与组成部分

2.1 网络爬虫的基本概念

网络爬虫是自动从互联网上抓取数据的程序,通过模拟人类阅读网页的行为,获取网页上的信息。它广泛应用于搜索引擎索引、数据挖掘和各种网络数据分析等领域。

2.1.1 网络爬虫的定义

一个网络爬虫通常包括一个初始的URL列表和一个爬取深度。它会遍历这个列表,按照爬取深度和定义的规则获取数据。在抓取过程中,爬虫会根据需要下载网页内容,解析出新的链接,然后继续抓取,直到完成既定目标。

2.1.2 爬虫的工作流程

网络爬虫的工作流程一般包括以下几个步骤:

  1. 从起始URL列表开始,爬虫向服务器发送HTTP请求。
  2. 服务器返回响应内容,爬虫分析HTML内容。
  3. 提取新的链接和需要的数据,形成新的请求。
  4. 将抓取的数据进行存储,通常是存储到文件或数据库。
  5. 如果还有未爬取的链接,重复步骤1-4。
  6. 关闭不再需要的连接,进行数据整理和分析。

2.2 网络爬虫的主要组成部分

网络爬虫的关键组成部分包括请求模块、响应处理、数据抓取和数据解析。

2.2.1 请求模块

请求模块负责发送HTTP请求,并获取响应。Python中requests库是实现这一功能的常用工具。

import requests

def get_page(url):
    try:
        response = requests.get(url)
        response.raise_for_status()  # 检查请求是否成功
        return response
    except requests.HTTPError as http_err:
        print(f'HTTP error occurred: {http_err}')
    except Exception as err:
        print(f'An error occurred: {err}')

page_content = get_page('http://example.com')

以上代码展示了使用requests库发起请求和异常处理的基本逻辑。通过 requests.get() 发起GET请求, response.raise_for_status() 检查返回的HTTP状态码。

2.2.2 响应处理

响应处理包括检查HTTP响应状态码、获取响应头信息、内容编码等。

def process_response(response):
    # 检查状态码是否为200
    if response.status_code == 200:
        print("Success!")
    else:
        print("Failed!")
    # 获取响应头信息
    headers = response.headers
    print(headers)

process_response(page_content)
2.2.3 数据抓取

数据抓取是从HTML内容中提取有用信息。这通常需要使用解析库如BeautifulSoup,来解析HTML并提取所需的数据。

from bs4 import BeautifulSoup

def extract_data(html_content):
    soup = BeautifulSoup(html_content, 'html.parser')
    # 提取网页标题
    title = soup.find('title').get_text()
    print(f"Page Title: {title}")

extract_data(page_content.text)
2.2.4 数据解析

数据解析是将提取的数据转化为结构化的形式,例如转化为字典或列表。对于JSON格式的数据,使用Python内置的 json 模块进行处理。

import json

def parse_json_data(json_str):
    try:
        data = json.loads(json_str)
        return data
    except json.JSONDecodeError:
        print("Invalid JSON data")

json_data = parse_json_data('{"name": "John", "age": 30, "city": "New York"}')
print(json_data)

上述代码展示了如何使用Python的 json 模块解析JSON字符串,并转化为Python字典。

通过上述几个子章节,本章对网络爬虫的基本概念、工作流程以及其主要组成部分进行了详细的介绍,并通过示例代码展示了如何在Python中实现这些组件。理解了这些基础概念之后,我们将在下一章深入学习如何使用BeautifulSoup库进行HTML解析。

3. BeautifulSoup库进行HTML解析

3.1 BeautifulSoup库的基础使用

3.1.1 BeautifulSoup库的安装

在开始使用BeautifulSoup进行HTML内容解析之前,第一步需要确保该库已经安装在你的Python环境中。可以通过pip命令来安装:

pip install beautifulsoup4

如果你使用的是Python 3,以上命令将安装最新版本的BeautifulSoup 4。该库是独立于Python版本的,也就是说,你不需要对不同的Python版本安装不同的BeautifulSoup版本。

3.1.2 BeautifulSoup的基本功能

BeautifulSoup是一个用于解析HTML和XML文档的库,它能够将复杂的HTML文档转换为一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为四种类型:Tag,NavigableString,BeautifulSoup和Comment。通过这些对象,我们可以轻松地定位和修改文档结构中的元素。

安装完成后,让我们开始基础使用。首先,我们需要从bs4模块导入BeautifulSoup类,并将一个HTML文档作为字符串或者文件对象传递给它:

from bs4 import BeautifulSoup

# 假设我们有一个简单的HTML字符串
html_doc = """
<html><head><title>The Dormouse's story</title></head>
      <body>
        <p class="title"><b>The Dormouse's story</b></p>
        <p class="story">Once upon a time there were three little sisters; and their names were
        <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
        <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
        <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
        and they lived at the bottom of a well.</p>
        <p class="story">...</p>
      </body>
</html>

# 创建一个BeautifulSoup对象
soup = BeautifulSoup(html_doc, 'html.parser')

# 打印soup对象,将输出解析后的文档结构
print(soup.prettify())

在上述代码中,我们创建了一个名为soup的BeautifulSoup对象,它将解析传入的HTML字符串。 prettify() 方法可以将解析后的内容格式化输出,以便于阅读。

一旦创建了这个对象,就可以使用它来执行各种搜索,例如搜索文档标题:

print(soup.title)
# 输出: <title>The Dormouse's story</title>

或者获取其文本内容:

print(soup.title.text)
# 输出: The Dormouse's story

或者搜索特定的标签(比如所有的 <a> 标签):

print(soup.find_all('a'))
# 输出: [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
#        <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
#        <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

BeautifulSoup非常强大,有许多方法可以用来导航、搜索和修改解析树。接下来,我们将深入探讨如何使用BeautifulSoup来提取网页数据。

3.2 BeautifulSoup在网页数据提取中的应用

3.2.1 标签选择和文本提取

BeautifulSoup使得从HTML文档中选择特定的标签变得非常简单。除了通过标签名(如上述的 find_all('a') )之外,还可以通过类名、ID或属性来查找标签。

通过类名选择标签
# 选择所有class为sister的<a>标签
sisters = soup.find_all('a', class_='sister')
通过ID选择标签
# 选择ID为link2的<a>标签
link2 = soup.find(id='link2')
通过属性选择标签
# 选择所有href属性包含example.com的<a>标签
example_links = soup.find_all('a', href=True)

选择到标签之后,我们可以获取其文本内容:

for sister in sisters:
    print(sister.text)
# 输出:
# Elsie
# Lacie
# Tillie

BeautifulSoup还允许我们获取标签的属性,例如获取链接的href属性:

for link in example_links:
    print(link['href'])
# 输出:
# http://example.com/elsie
# http://example.com/lacie
# http://example.com/tillie

3.2.2 遍历解析树

除了查找特定标签之外,BeautifulSoup还允许我们遍历整个解析树,这在提取结构化数据时非常有用。

遍历标签的子节点
# 获取<p>标签的子节点
children = soup.title.children
for child in children:
    print(child)
# 输出:
# The Dormouse's story
获取所有兄弟节点
# 获取<a>标签的所有兄弟节点
brothers = soup.find('a').next_siblings
for brother in brothers:
    print(brother)
# 输出:
# and they lived at the bottom of a well.
获取父节点
# 获取<a>标签的父节点
parent = soup.find('a').parent
print(parent)
# 输出: <p class="story">Once upon a time there were three little sisters; and their names were
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
# and they lived at the bottom of a well.</p>

3.2.3 高级搜索技巧

BeautifulSoup还提供了一些高级搜索功能,比如CSS选择器匹配和lambda函数过滤。

使用CSS选择器

BeautifulSoup支持大部分CSS选择器,这对于熟悉jQuery或CSS选择器的开发者来说非常方便。

# 使用CSS选择器选择所有具有类名sister的<a>标签
sisters = soup.select('a.sister')
for sister in sisters:
    print(sister)
使用lambda表达式过滤标签

BeautifulSoup还允许使用lambda函数进行复杂的过滤。

# 使用lambda函数选择所有文本包含'Elsie'的<a>标签
elsie_links = soup.find_all(lambda tag: tag.name == 'a' and 'Elsie' in tag.text)
for link in elsie_links:
    print(link)

通过以上几个小节,我们已经了解了BeautifulSoup库在HTML解析中的基础使用方法,包括如何安装和初始化BeautifulSoup对象,如何进行标签选择和文本提取,如何遍历解析树以及如何使用高级搜索技巧来筛选特定的HTML内容。BeautifulSoup是一个强大的工具,能够轻松地解析HTML并提取所需数据,广泛应用于数据抓取、爬虫开发以及其他需要HTML解析的场景中。

在下一节中,我们将继续深入探讨BeautifulSoup的高级应用,例如如何处理嵌套标签,如何使用正则表达式进行搜索,以及如何操作和修改HTML文档。通过这些高级功能,我们可以更加灵活地处理复杂的HTML结构,并且实现更加精确的数据抓取。

3.3 BeautifulSoup的高级应用

3.3.1 嵌套标签的处理

嵌套标签是HTML文档中常见的结构,处理它们对于从文档中提取数据至关重要。BeautifulSoup提供了许多方法来处理嵌套标签,这些方法包括但不限于搜索、过滤和导航。

搜索嵌套标签
# 选择嵌套在<p>标签内的<b>标签
bold_text = soup.find('p').find('b')
print(bold_text)
# 输出: <b>The Dormouse's story</b>
过滤嵌套标签
# 过滤出所有嵌套在<p>标签内的<a>标签
nested_links = soup.find('p').find_all('a')
for link in nested_links:
    print(link)
导航嵌套标签

BeautifulSoup的导航方法允许开发者轻松地访问文档的不同部分。导航方法包括 contents children descendants

# 获取<p>标签的所有内容
p_contents = soup.find('p').contents
print(p_contents)

3.3.2 使用正则表达式进行搜索

BeautifulSoup允许使用正则表达式在标签内容上进行复杂的搜索。这对于需要精确匹配的场景尤其有用。

import re

# 使用正则表达式搜索包含'Elsie'的<a>标签
elsie_links = soup.find_all('a', string=re.compile("Elsie"))
for link in elsie_links:
    print(link)

3.3.3 操作和修改HTML文档

BeautifulSoup不仅可以用于搜索和提取文档内容,还可以用于修改文档结构。

修改标签文本
# 修改<a>标签的文本
for link in soup.find_all('a'):
    link.string = link.string.upper()
print(soup.prettify())
添加新标签
# 在文档中添加一个新的<a>标签
new_link = soup.new_tag("a", href="http://newpage.com", title="New Page")
soup.body.append(new_link)

print(soup.prettify())

通过以上的方法,我们可以了解到BeautifulSoup不仅在HTML解析中提供了强大的基础功能,而且在处理嵌套标签、使用正则表达式搜索以及操作和修改HTML文档方面也表现出了极大的灵活性。这些高级功能为开发者提供了更多的数据抓取工具,使得数据提取变得更加精确和高效。

在掌握了BeautifulSoup库的基础使用和高级应用之后,我们可以利用它来处理更复杂的HTML内容,无论是在数据抓取还是在网页自动化测试中,BeautifulSoup都将是一个不可或缺的工具。随着对BeautifulSoup的深入学习,开发者将能够更好地掌握数据抓取的艺术,从而在项目中实现更丰富的功能。

4. JSON数据格式处理

4.1 JSON数据格式的理解

4.1.1 JSON数据结构介绍

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。JSON基于JavaScript的一个子集,其数据格式可以简单地描述为:一个字符串,它由键值对组成,使用逗号分隔,并且被大括号包围起来以形成一个对象。键和字符串值都用双引号包围。

JSON数据结构可以包含如下几种类型:

  • 对象:一个键值对的集合。在JavaScript中,对象实际上就是无序的键值对。
  • 数组:一个值的有序集合。在JavaScript中,数组是一种特殊类型的对象。
  • 字符串:一个由双引号包围的文本序列。
  • 数字:没有引号的十进制数字。
  • 布尔值:true 或 false。
  • null:表示空值。

4.1.2 JSON与Python数据类型的转换

Python 语言中自带了处理 JSON 的模块,称为 json 。这个模块可以让我们很方便地将 Python 中的字典和列表等数据类型转换为 JSON 格式的字符串,同时也能够将 JSON 格式的字符串转换回 Python 的数据类型。

一个典型的操作流程如下:

  • 使用 json.dumps() 方法将 Python 字典转换为 JSON 格式的字符串。
  • 使用 json.loads() 方法将 JSON 格式的字符串转换回 Python 的字典类型。

例如,下面是一个简单的 Python 示例代码:

import json

# Python 字典转换为 JSON 字符串
python_dict = {'name': 'John', 'age': 30, 'city': 'New York'}
json_string = json.dumps(python_dict)
print(json_string)

# JSON 字符串转换回 Python 字典
python_dict_from_json = json.loads(json_string)
print(python_dict_from_json)

执行逻辑说明:

  • 在该代码块中,我们首先导入 Python 标准库中的 json 模块。
  • 使用 json.dumps() 方法将一个 Python 字典转换成一个 JSON 格式的字符串。
  • 然后,我们使用 json.loads() 方法将这个 JSON 字符串转换回 Python 字典格式,以证明转换过程是可逆的。

参数说明:

  • json.dumps() 方法的参数可以是一个字典,也可以是一个列表或其它可被序列化的数据结构。
  • json.loads() 方法的参数必须是一个 JSON 格式的字符串。

4.2 在网络爬虫中处理JSON数据

4.2.1 从网络响应中解析JSON

当我们在进行网络爬虫开发时,经常需要从目标网站的 API 获取数据。这些数据通常以 JSON 格式返回。因此,我们需要从 HTTP 响应中提取 JSON 数据。

以下是一个 Python 示例代码,演示了如何从网络响应中提取 JSON 数据:

import requests
import json

# 发送HTTP GET请求
response = requests.get('https://api.example.com/data')

# 检查请求是否成功
if response.status_code == 200:
    # 解析JSON数据
    data = response.json()
    print(data)
else:
    print('Failed to retrieve data:', response.status_code)

执行逻辑说明:

  • 使用 requests.get() 方法发起 HTTP GET 请求。
  • 通过检查 HTTP 响应的状态码确认请求是否成功。
  • 如果请求成功(HTTP 响应状态码为 200),使用 response.json() 方法解析响应的内容为 Python 对象。
  • 如果请求失败,打印出失败状态码。

参数说明:

  • requests.get() 方法会接受一个 URL 字符串作为参数,并返回一个 Response 对象。
  • response.json() 方法会解析这个 Response 对象的内容,并返回 Python 数据结构。

4.2.2 构造和发送JSON数据请求

在一些情况下,我们需要向服务器发送数据,如在执行登录、数据提交等操作时。通常,我们会将数据封装为 JSON 格式,并作为请求体发送。

下面是一个 Python 示例代码,演示了如何构造一个包含 JSON 数据的 POST 请求:

import requests
import json

# 要发送的数据
data_to_send = {'username': 'user1', 'password': 'pass123'}

# 发送HTTP POST请求
response = requests.post('https://api.example.com/login', json=data_to_send)

# 检查请求是否成功
if response.status_code == 200:
    print('Login successful')
else:
    print('Login failed:', response.status_code)

执行逻辑说明:

  • 我们首先构造了一个包含登录信息的 Python 字典。
  • 使用 requests.post() 方法发起一个 HTTP POST 请求。我们把目标 URL 和数据作为参数传递给该方法。
  • requests 库会自动将 Python 字典转换为 JSON 格式,并将其作为请求体发送。这得益于 requests 库的 json= 参数。
  • 与前面的例子类似,我们需要检查服务器的响应状态码来确认请求是否成功。

参数说明:

  • requests.post() 方法接受目标 URL 和一个可选的 json= 参数。如果 json= 参数提供了一个字典, requests 库会自动将该字典序列化为 JSON 数据,并设置正确的 HTTP 头部信息。

通过以上示例代码,我们可以看到如何从网络响应中解析 JSON 数据以及如何构造并发送包含 JSON 数据的请求。这些操作在实际的网络爬虫项目中是十分常见的,因此熟练掌握这些技能对于一个爬虫开发者来说至关重要。

5. 异常处理与重试机制

5.1 异常处理的重要性

网络爬虫在执行过程中,由于网络问题、目标网站结构变化、服务器异常等原因,很容易遇到各种异常。妥善处理这些异常,可以确保爬虫程序的稳定运行和数据的正确抓取。

5.1.1 网络爬虫中的常见异常

网络爬虫中的常见异常包括但不限于以下几类:

  • 网络连接异常 :如 requests.exceptions.ConnectionError ,发生于无法与服务器建立连接时。
  • 超时异常 :如 requests.exceptions.Timeout ,当请求超出了设定的等待时间仍未返回时抛出。
  • 重定向异常 :如 requests.exceptions.TooManyRedirects ,当请求重定向次数过多时抛出。
  • 请求异常 :如 requests.exceptions.RequestException ,这是所有请求相关异常的基类。

5.1.2 异常处理策略

针对不同的异常类型,我们可以采取不同的处理策略:

  • 捕获异常 :通过try-except语句块捕获可能发生的异常,并针对不同的异常类型执行相应的处理逻辑。
  • 重试机制 :如果捕获到的是可恢复的异常,如超时和网络连接问题,可以采用重试机制。
  • 记录日志 :记录异常信息可以帮助开发者了解爬虫在运行过程中遇到的问题,并进行针对性优化。
  • 异常反馈 :将异常信息反馈给用户或开发者,以便进行调试和修正。

5.2 实现重试机制

重试机制是保证爬虫稳定运行的重要手段之一。合理设计重试机制可以有效避免因单次失败导致的爬取任务中断。

5.2.1 重试机制的设计原理

重试机制设计时需要考虑以下因素:

  • 重试次数 :过多的重试会增加服务器负担,过少则可能导致数据丢失。通常设置3-5次重试。
  • 重试间隔 :为了避免对服务器造成过大压力,重试之间应有适当的时间间隔,例如每隔几秒重试一次。
  • 异常类型 :有些异常类型不适合重试,例如无效请求或用户认证失败等。

5.2.2 代码实现重试机制的方法

接下来我们通过一个简单的Python代码示例,展示如何实现重试机制:

import requests
from requests.exceptions import RequestException

def request_with_retry(url, max_retries=3, backoff_factor=1):
    retry_count = 0
    while retry_count < max_retries:
        try:
            response = requests.get(url)
            response.raise_for_status()  # Raise HTTPError if the HTTP request returned an unsuccessful status code
            return response
        except RequestException as e:
            print(f"Request failed: {e}, retrying ({retry_count+1}/{max_retries})")
            retry_count += 1
            if retry_count == max_retries:
                raise
            time.sleep(backoff_factor * (2 ** (retry_count - 1)))

# 使用示例
try:
    response = request_with_retry('https://www.example.com')
except RequestException as e:
    print(f"Final request failed: {e}")

在这个例子中,我们定义了一个名为 request_with_retry 的函数,它会尝试发送HTTP GET请求到指定的URL,并在遇到异常时进行重试。重试次数由 max_retries 参数控制,重试间隔则通过 backoff_factor 乘以2的幂来实现递增。

上述代码中还包含了一个简单的指数退避策略(backoff strategy),这是一种避免在短时间内对服务器进行过多重试的有效方法。指数退避策略通过逐渐增加等待时间,以减少请求之间的冲突,以及对目标服务器的压力。

在实现重试机制时,还应该考虑异常类型,有些异常不应该重试,例如HTTP 404错误(页面不存在)或者403错误(权限不足)。这些情况重试通常无意义,反而会造成资源的浪费。

在实际应用中,还应结合业务需求,为特定的异常类型制定更为细致的处理策略。通过以上这些方法,可以有效提高网络爬虫的健壮性和可用性。

6. 分页信息处理与防止IP封禁策略

6.1 分页信息的识别与处理

6.1.1 分页的类型与识别方法

在处理网络爬虫中的分页信息时,理解分页的类型是至关重要的。常见的分页类型包括基于页面链接的分页、基于查询参数的分页以及基于Ajax异步加载的分页。每一种分页类型都有其特定的识别方法,这通常涉及到对网页结构的深入分析。

  • 页面链接分页通常在网页中体现为一系列的页面链接,或者是前进、后退的翻页按钮。这种分页的识别方法通常依赖于链接的规律性,如连续的数字序列或者是特定的翻页模式。
  • 查询参数分页则更隐蔽,它通过URL的查询字符串来传递分页信息,如 ?page=1 。要识别这种分页,需要分析请求的URL,观察在翻页过程中,URL的哪个部分在发生变化。

  • Ajax异步加载分页是最难处理的,因为数据可能是通过JavaScript动态加载的。在这种情况下,可能需要借助浏览器的开发者工具,分析网络请求,找到对应的Ajax请求链接。

具体的操作步骤可以是:
1. 使用浏览器的开发者工具(通常为F12键)查看页面。
2. 分析页面结构,查看是否有明显的翻页链接或按钮。
3. 查看网络请求记录,特别是通过翻页后新增的网络请求。
4. 观察URL参数的变化,或Ajax请求体中包含的分页信息。

6.1.2 分页信息的自动化处理

在识别了分页类型后,接下来是实现分页信息的自动化处理。这一过程需要根据不同的分页类型采取不同的策略:

  • 对于页面链接分页,可以通过请求分页对应的URL来获取数据。
  • 对于查询参数分页,可以通过构造不同的查询参数(例如改变 page 的值)来访问不同页的数据。

  • 对于Ajax异步加载分页,可能需要对Ajax请求进行模拟。这通常包括提取出请求的URL和可能需要的Headers(如 X-Requested-With:XMLHttpRequest )、Cookies等,然后使用requests库发送HTTP请求。

下面是一个简单的代码示例,演示了如何处理基于查询参数的分页:

import requests
from bs4 import BeautifulSoup

base_url = 'https://example.com/items?page='

def get_page_content(page_number):
    url = base_url + str(page_number)
    response = requests.get(url)
    soup = BeautifulSoup(response.text, 'html.parser')
    return soup.find_all('div', class_='item')  # 假设每个item都在class为'item'的div标签内

# 获取第一页的数据
page_content = get_page_content(1)
# ... 进行数据处理

# 获取第二页的数据
page_content = get_page_content(2)
# ... 进行数据处理

# 循环处理所有分页
for page in range(1, 11):  # 假设我们只想获取前10页的数据
    page_content = get_page_content(page)
    # ... 进行数据处理

在上述代码中,我们定义了一个 get_page_content 函数,它接收 page_number 作为参数,构造相应的URL并发送请求。随后使用BeautifulSoup解析返回的HTML内容,并提取特定的数据。

6.1.3 分页信息处理的实际应用

为了进一步说明分页信息的自动化处理,下面是一个使用requests库和BeautifulSoup库来处理分页信息的实际应用例子:

import requests
from bs4 import BeautifulSoup

def fetch_items_with_paging(base_url, pages):
    all_items = []
    for page_number in range(1, pages + 1):
        response = requests.get(base_url + str(page_number))
        if response.status_code == 200:
            soup = BeautifulSoup(response.text, 'html.parser')
            items = soup.find_all('div', class_='item')
            all_items.extend(items)
        else:
            print(f"Failed to fetch page {page_number}")
    return all_items

# 假设我们有一个基于查询参数的分页网站,其基础URL如下:
base_url = 'https://example.com/shop/items?page='
pages_to_fetch = 5

items = fetch_items_with_paging(base_url, pages_to_fetch)
# 接下来可以对items进行处理,比如存储到数据库或进行分析

在上述代码段中,我们定义了一个 fetch_items_with_paging 函数,它接收 base_url pages 作为参数,循环请求每个分页的URL,并提取分页中的项目(items),最后返回所有获取到的项目。这是一个典型的应用分页信息处理与自动化请求结合的场景。

6.2 防止IP封禁的策略

6.2.1 IP封禁的原因分析

网络爬虫在进行大规模数据抓取时,往往会对目标服务器造成较大的访问压力,这有时会导致服务器的IP地址被暂时或永久封禁。IP封禁的原因大致可以分为以下几点:

  • 高频率访问 :爬虫在短时间内发送过多的请求,导致服务器负载过高。
  • 访问模式异常 :爬虫的行为不符合正常用户的访问模式,例如短时间内对同一页面的反复访问。
  • 请求头信息异常 :爬虫的请求头信息中可能包含一些不寻常的值,如User-Agent过于常见或不常见。

针对上述原因,开发者在设计爬虫时需要考虑如何减少对目标服务器的影响,避免被封禁。

6.2.2 实现IP轮换和代理IP的策略

为了减少爬虫对服务器的访问压力,同时避免IP地址被封禁,可以采取以下策略:

  • IP轮换 :在爬虫设计中使用多个IP地址进行轮换,从而避免对单一IP地址的依赖和过度使用。
  • 代理IP :使用代理IP池,每次请求时随机或按照一定规则选择一个代理IP进行访问。

下面是一个简单的代理IP使用示例:

import requests
from fake_useragent import UserAgent

# 设置代理IP池
proxies = {
    'http': 'http://10.10.1.10:3128',
    'https': 'http://10.10.1.12:8080',
    # ... 可以配置更多的代理IP
}

# 使用fake_useragent库生成随机的User-Agent
ua = UserAgent()

headers = {
    'User-Agent': ua.random
}

url = 'https://example.com'

response = requests.get(url, proxies=proxies, headers=headers)

# 检查响应状态,并根据响应内容决定是否继续使用该代理IP
if response.status_code == 200:
    # 处理响应内容
    pass
else:
    # 可以将该代理IP从代理池中移除或标记为不可用
    pass

在这个示例中,我们首先设置了一个代理IP池 proxies ,然后使用 fake_useragent 库生成了一个随机的User-Agent,这样可以模拟不同浏览器的访问行为。通过在requests库中设置 proxies 参数,可以指定使用代理IP进行网络请求。

通过上述方法,可以有效减少爬虫对目标服务器的压力,降低被封禁的风险,提高爬虫的稳定性和可用性。需要注意的是,使用代理IP时,要确保代理服务器的可靠性和响应速度,避免引入过高的延迟或者数据传输上的不稳定性。

7. 数据存储技术与爬虫框架Scrapy简介

7.1 数据存储技术的选择

7.1.1 数据存储的方式对比

在网络爬虫项目中,数据存储是一个关键的环节。通常来说,数据存储的方式可以分为以下几类:

  • 文件存储 :如CSV、JSON、XML等。这种方式实现简单,但不便于查询和索引操作,且对于大规模数据存储不够高效。
  • 关系型数据库 :如MySQL、PostgreSQL等。这类数据库结构化程度高,支持复杂的查询,适合需要高度结构化存储的应用场景。
  • NoSQL数据库 :如MongoDB、Redis等。NoSQL数据库适合存储大量的非结构化或半结构化数据,能够提供灵活的数据模型和良好的水平扩展能力。

7.1.2 数据库存储实践

对于网络爬虫项目,通常推荐使用关系型数据库或NoSQL数据库进行数据存储。下面以关系型数据库MySQL为例,展示如何实践数据存储:

首先,建立数据库和数据表:

CREATE DATABASE IF NOT EXISTS CrawlerDB;
USE CrawlerDB;

CREATE TABLE IF NOT EXISTS `items` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  `link` varchar(255) NOT NULL,
  `published_date` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

然后,在爬虫项目中使用Python连接数据库并存储数据:

import mysql.connector
from mysql.connector import Error

def insert_item(item):
    connection = None
    try:
        connection = mysql.connector.connect(
            host='localhost',
            database='CrawlerDB',
            user='your_username',
            password='your_password'
        )
        if connection.is_connected():
            db_info = connection.get_server_info()
            cursor = connection.cursor()
            insert_query = "INSERT INTO items (title, link, published_date) VALUES (%s, %s, %s)"
            cursor.execute(insert_query, (item['title'], item['link'], item['published_date']))
            connection.commit()
            print("Item inserted successfully")
    except Error as e:
        print(f"Error: {e}")
    finally:
        if connection and connection.is_connected():
            cursor.close()
            connection.close()

7.2 爬虫框架Scrapy的介绍与使用

7.2.1 Scrapy框架的特点与优势

Scrapy是一个快速的高层次web爬取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。它的特点与优势包括:

  • 高度可扩展 :Scrapy是模块化的,允许用户快速扩展其功能。
  • 异步处理能力 :Scrapy使用Twisted网络框架,可以在不牺牲易用性的前提下,处理大量的并发请求。
  • 中间件 :提供中间件扩展点,允许用户自定义数据处理的流程。
  • Item Pipeline :方便数据的清洗、验证、存储。
  • 选择器 :Scrapy的选择器使用XPath和CSS表达式,可以方便地提取HTML/XML文档中的数据。

7.2.2 Scrapy框架的基本使用示例

下面是一个简单的Scrapy爬虫示例,用于抓取quotes.toscrape.com上的名言及其作者。

首先,创建Scrapy项目:

scrapy startproject quotes_scraper
cd quotes_scraper

然后,定义Item(数据模型):

import scrapy

class QuoteItem(scrapy.Item):
    text = scrapy.Field()
    author = scrapy.Field()
    tags = scrapy.Field()

接下来,编写Spider来抓取数据:

import scrapy
from quotes_scraper.items import QuoteItem

class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    allowed_domains = ['quotes.toscrape.com']
    start_urls = ['http://quotes.toscrape.com/']

    def parse(self, response):
        for quote in response.css('div.quote'):
            item = QuoteItem()
            item['text'] = quote.css('span.text::text').get()
            item['author'] = quote.css('span small::text').get()
            item['tags'] = quote.css('div.tags a.tag::text').getall()
            yield item

        next_page = response.css('li.next a::attr(href)').get()
        if next_page is not None:
            yield response.follow(next_page, self.parse)

最后,配置Item Pipeline来存储数据到文件:

import json

class JsonWriterPipeline(object):
    def open_spider(self, spider):
        self.file = open('quotes.json', 'w')

    def close_spider(self, spider):
        self.file.close()

    def process_item(self, item, spider):
        line = json.dumps(dict(item)) + "\n"
        self.file.write(line)
        return item

并在settings.py中启用该Pipeline:

ITEM_PIPELINES = {
   'quotes_scraper.pipelines.JsonWriterPipeline': 300,
}

以上即为Scrapy框架的基本使用案例,这个案例展示了如何构建一个简单的爬虫,并将数据存储到JSON文件中。Scrapy框架的功能远不止如此,它还支持更复杂的场景,包括但不限于延迟下载、中间件扩展、多个数据源抓取等。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:网络爬虫是自动化获取互联网数据的常用技术,本项目使用Python的requests库从京东网站抓取商品详情和用户评论。内容涵盖requests库的使用、爬虫基本原理、HTML和JSON数据解析、异常处理、分页处理、防封IP策略、数据存储方法,以及合法道德爬虫的重要性。学习此项目有助于掌握网络爬虫技术并为数据分析打基础。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

Logo

加入社区!打开量化的大门,首批课程上线啦!

更多推荐