xChar
·25 days ago

一、爬虫初印象

在互联网的广阔世界里,数据如同宝藏般散落各处。而爬虫,就像是一位勤劳的寻宝者,能够按照特定规则,自动地在网页间穿梭,抓取我们所需的信息。简单来说,它是一段能自动获取网页数据的程序或脚本 ,其正式名称是网络爬虫(Web Crawler),也常被称为网页蜘蛛、网络机器人 。

爬虫在数据获取方面扮演着举足轻重的角色。如今,数据已成为企业和研究人员决策的关键依据,而爬虫则是获取大量数据的高效手段。它的应用场景极为广泛,在数据分析领域,通过爬虫采集社交媒体平台上的用户评论和行为数据,能够助力企业精准洞察用户需求与市场趋势,为产品优化和营销策略制定提供有力支撑。在竞品调研中,爬虫可以定期抓取竞争对手的产品信息、价格动态以及促销活动等,帮助企业及时调整自身策略,保持竞争力。此外,在学术研究、新闻资讯聚合等方面,爬虫也发挥着不可替代的作用 。

二、环境搭建与基础语法

2.1 Python安装与配置

Python是爬虫开发的首选语言,其简洁的语法和丰富的库能够极大地简化开发过程 。首先,我们需要从Python官方网站(https://www.python.org/downloads/ )下载适合你操作系统的安装包。在下载页面,你可以看到各种版本的Python,建议选择最新的稳定版本。下载完成后,运行安装包,在安装向导中,务必勾选“Add Python to PATH”选项,这一步非常关键,它能确保Python可在系统的任何路径下被调用 。

安装完成后,可以通过在命令提示符(CMD)中输入python --version来验证是否安装成功。如果成功安装,你将看到Python的版本号信息。此外,还可以输入python进入Python交互式环境,在这里可以直接编写和执行Python代码,体验Python的魅力 。

2.2 开发工具选择

一个好的开发工具能够显著提高开发效率。在爬虫开发中,PyCharm是一款备受青睐的集成开发环境(IDE) 。它具有强大的代码编辑功能,如代码自动补全、语法高亮、代码导航等,能让你在编写代码时更加得心应手。同时,PyCharm对Python的各种库和框架有很好的支持,方便进行项目管理和调试 。

除了PyCharm,还有其他一些不错的选择,如Visual Studio Code(VS Code)。它是一款轻量级但功能强大的代码编辑器,通过安装Python插件,同样能实现高效的Python开发。VS Code具有良好的扩展性和跨平台性,适合喜欢简洁开发环境的开发者 。

2.3 Python基础语法回顾

在正式开始爬虫开发前,回顾一下Python的基础语法是很有必要的。这包括数据类型、控制语句和函数等 。

Python有多种基本数据类型,例如整数(int)、浮点数(float)、字符串(str)、布尔值(bool)等。不同的数据类型在存储和操作数据时各有特点 。比如,字符串用于存储文本信息,你可以通过索引和切片操作来获取字符串中的特定字符或子串 。示例代码如下:

name = "爬虫小能手"

print(name\[0])  # 输出第一个字符

print(name\[2:5])  # 输出从第三个字符到第五个字符的子串

控制语句是程序逻辑的重要组成部分,常见的有条件语句(if - elif - else)和循环语句(for、while)。条件语句用于根据不同的条件执行不同的代码块,循环语句则用于重复执行某段代码 。例如,使用for循环遍历一个列表:

fruits = \["苹果", "香蕉", "橙子"]

for fruit in fruits:

      print(fruit)

函数是将一段可重复使用的代码封装起来的工具,它可以提高代码的复用性和可读性 。在Python中,你可以使用def关键字定义函数,例如:

def add\_numbers(a, b):

      return a + b

result = add\_numbers(3, 5)

print(result)  # 输出8

通过对这些基础语法的掌握,我们为后续的爬虫开发奠定了坚实的基础。

三、爬虫基础原理与流程

3.1 HTTP协议解析

HTTP协议,即超文本传输协议,是爬虫与网页服务器进行通信的基础 。它就像是爬虫与服务器之间的通用语言,规定了双方如何进行数据的请求和传输 。

HTTP请求主要由请求行、请求头、请求体(可选)组成 。请求行包含了请求方法、URL和HTTP版本。常见的请求方法有GET和POST 。GET方法通常用于从服务器获取资源,比如访问网页时,浏览器会向服务器发送GET请求,获取网页的HTML内容。在使用GET请求时,参数会附加在URL的末尾,以键值对的形式呈现,例如https://example.com/search?q=``爬虫&page=1 ,这种方式使得参数在URL中可见,因此不太适合传输敏感信息 。

POST方法则常用于向服务器提交数据,比如登录表单、提交评论等操作 。与GET不同,POST请求的参数放在请求体中,对用户不可见,安全性相对较高 。例如,在登录时,用户名和密码会通过POST请求发送到服务器,请求体中可能包含类似username=admin&password=123456的内容 。

HTTP响应由状态行、响应头、响应体组成 。状态行中的状态码能直观地反映请求的处理结果 。例如,200表示请求成功,服务器成功返回了所请求的资源;404表示请求的资源不存在,可能是URL输入错误或页面已被删除;500表示服务器内部出现错误 。响应头包含了关于响应的一些元信息,如内容类型(如text/html表示返回的是HTML页面)、内容长度等 。而响应体则是我们真正想要获取的数据,比如网页的HTML代码、JSON格式的数据等 。

3.2 爬虫工作流程

爬虫的工作流程可以概括为发起请求、获取响应、解析数据和保存数据这几个关键步骤 。

首先,爬虫会根据设定的URL,使用HTTP库(如Python中的requests库)向目标服务器发起请求 。在这个过程中,为了模拟真实用户的访问,可能会设置请求头,例如User - Agent,它可以告诉服务器访问者使用的浏览器类型和操作系统等信息 。例如,以下代码使用requests库发起一个GET请求:

import requests

url = "https://example.com"

headers = {

      "User - Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"

}

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

服务器接收到请求后,会返回相应的响应 。如果请求成功,我们会得到一个包含状态码、响应头和响应体的响应对象 。爬虫获取到响应后,接下来就是从响应体中提取出我们需要的数据 。这一步需要根据数据的格式选择合适的解析方法 。如果响应体是HTML格式,可以使用BeautifulSouplxml等库进行解析 。例如,使用BeautifulSoup解析HTML页面,提取所有的链接:

from bs4 import BeautifulSoup

soup = BeautifulSoup(response.text, 'html.parser')

links = soup.find\_all('a')

for link in links:
  print(link.get('href'))

若响应体是JSON格式的数据,可以使用Python内置的json模块进行解析 。示例如下:

import json

data = json.loads(response.text)

print(data)

最后,将解析得到的数据保存到本地文件或数据库中,以便后续的分析和使用 。保存到文件的常见格式有文本文件(.txt)、CSV文件(.csv)、JSON文件(.json)等 。例如,将数据保存为JSON文件:

import json

data = \[{"name": "爬虫", "info": "数据采集工具"}]

with open('data.json', 'w', encoding='utf - 8') as f:
  json.dump(data, f, ensure\_ascii=False, indent=4)

如果需要保存到数据库,对于关系型数据库(如MySQL),可以使用pymysql库;对于非关系型数据库(如MongoDB),可以使用pymongo库 。

四、爬虫常用库实战

4.1 Requests库

Requests库是Python中用于发送HTTP请求的利器,它的API简洁明了,让我们能够轻松地与网页服务器进行交互 。在使用Requests库时,首先要确保已经安装,可以通过pip install requests命令进行安装 。

安装完成后,就可以在代码中使用它了。例如,发送一个简单的GET请求来获取网页内容:

import requests

url = "https://www.example.com"

response = requests.get(url)

if response.status\_code == 200:

      print(response.text)

else:

      print(f"请求失败,状态码: {response.status\_code}")

在这个例子中,requests.get(url)向指定的URL发送GET请求,并返回一个响应对象response 。通过检查response.status_code,我们可以判断请求是否成功。如果状态码为200,说明请求成功,response.text中包含了网页的HTML内容 。

除了GET请求,Requests库还支持POST请求,用于向服务器提交数据。例如,模拟登录表单提交:

import requests

url = "https://www.example.com/login"

data = {

      "username": "your\_username",

      "password": "your\_password"

}

response = requests.post(url, data = data)

print(response.text)

在这个代码中,data字典包含了登录所需的用户名和密码,requests.post(url, data = data)将这些数据发送到指定的登录URL 。

此外,还可以通过设置请求头来模拟不同的浏览器访问,以及处理响应的JSON数据、设置请求超时等 。例如,设置请求头:

import requests

url = "https://www.example.com"

headers = {

      "User - Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"

}

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

print(response.text)

在这个例子中,headers字典设置了User - Agent,告诉服务器我们使用的是Chrome浏览器 。这样可以避免一些网站因为检测到非浏览器访问而拒绝请求 。

4.2 BeautifulSoup库

BeautifulSoup库是专门用于解析HTML和XML数据的强大工具 。它能够将复杂的HTML或XML文档转换成一个易于遍历和操作的树形结构,让我们可以轻松地提取所需的数据 。在使用BeautifulSoup库之前,需要先安装,可以通过pip install beautifulsoup4命令进行安装 。

假设我们已经使用Requests库获取了网页的HTML内容,接下来就可以使用BeautifulSoup库进行解析 。例如:

from bs4 import BeautifulSoup

import requests

url = "https://www.example.com"

response = requests.get(url)

if response.status\_code == 200:

      soup = BeautifulSoup(response.text, 'html.parser')

      # 提取所有的链接

      links = soup.find\_all('a')

      for link in links:

          print(link.get('href'))

else:

      print(f"请求失败,状态码: {response.status\_code}")

在这个代码中,BeautifulSoup(response.text, 'html.parser')将获取到的HTML内容解析成一个BeautifulSoup对象souphtml.parser是解析器,这里使用的是Python内置的HTML解析器,也可以根据需要选择其他解析器,如lxmlsoup.find_all('a')用于查找所有的<a>标签,即链接,并通过link.get('href')获取每个链接的href属性值 。

除了通过标签名查找元素,还可以通过类名、ID等属性进行查找 。例如,查找具有特定类名的元素:

from bs4 import BeautifulSoup

import requests

url = "https://www.example.com"

response = requests.get(url)

if response.status\_code == 200:

      soup = BeautifulSoup(response.text, 'html.parser')

      # 查找类名为 "special - class" 的元素

      special\_elements = soup.find\_all(class\_='special - class')

      for element in special\_elements:

          print(element.get\_text())

else:

      print(f"请求失败,状态码: {response.status\_code}")

在这个例子中,soup.find_all(class_='special - class')查找所有类名为special - class的元素,并通过element.get_text()获取这些元素的文本内容 。

4.3 XPath语法

XPath是一种用于在XML和HTML文档中定位和提取元素的语言 。它通过定义路径表达式,能够精准地选取文档中的节点或节点集,在爬虫开发中具有重要的应用 。在Python中,可以结合lxml库来使用XPath语法 。首先,需要安装lxml库,通过pip install lxml命令进行安装 。

下面是一个使用XPath语法提取网页数据的示例:

from lxml import etree

import requests

url = "https://www.example.com"

response = requests.get(url)

if response.status\_code == 200:

      html = etree.HTML(response.text)

      # 提取所有的 \<p> 标签的文本内容

      p\_texts = html.xpath('//p/text()')

      for text in p\_texts:

          print(text)

else:

      print(f"请求失败,状态码: {response.status\_code}")

在这个代码中,etree.HTML(response.text)将获取到的HTML内容转换为lxmlElement对象htmlhtml.xpath('//p/text()')使用XPath表达式//p/text()选取所有<p>标签内的文本内容 。其中,//表示从当前节点开始选择文档中的节点,不考虑它们的位置;p是标签名;/text()表示选取该标签内的文本 。

XPath语法还支持通过属性来定位元素。例如,提取具有特定属性值的元素:

from lxml import etree

import requests

url = "https://www.example.com"

response = requests.get(url)

if response.status\_code == 200:

      html = etree.HTML(response.text)

      # 提取class为 "article - content" 的 \<div> 标签内的所有链接

      links = html.xpath('//div\[@class="article - content"]//a/@href')

      for link in links:

          print(link)

else:

      print(f"请求失败,状态码: {response.status\_code}")

在这个例子中,//div[@class="article - content"]表示选取所有class属性值为article - content<div>标签,//a/@href表示在这些<div>标签内继续选取所有<a>标签的href属性值 。

4.4 正则表达式

正则表达式是一种用于匹配和处理字符串的强大工具,在爬虫的数据提取中也经常被用到 。它通过定义一系列的规则来匹配符合特定模式的字符串 。在Python中,通过内置的re模块来支持正则表达式 。

例如,假设我们要从一段文本中提取所有的电话号码,可以使用如下正则表达式:

import re

text = "联系电话:13888888888,另一个电话:15666666666"

pattern = r'\d{11}'

phones = re.findall(pattern, text)

for phone in phones:

      print(phone)

在这个代码中,r'\d{11}'是正则表达式模式。其中,r表示这是一个原始字符串,防止反斜杠字符被转义;\d表示匹配任何一个数字字符(0 - 9);{11}表示前面的字符(即数字)连续出现11次 。re.findall(pattern, text)在给定的文本text中查找所有符合正则表达式模式pattern的字符串,并返回一个列表 。

正则表达式还可以用于匹配更复杂的模式,如电子邮件地址、URL等 。例如,匹配电子邮件地址:

import re

text = "邮箱:[email protected],另一个邮箱:[email protected]"

pattern = r'\[a-zA-Z0-9\_.+-]+@\[a-zA-Z0-9-]+\\.\[a-zA-Z0-9-.]+'

emails = re.findall(pattern, text)

for email in emails:

      print(email)

在这个例子中,[a-zA-Z0-9_.+-]+表示由字母、数字、下划线、点、加号和减号组成的一个或多个字符;@是电子邮件地址的固定符号;[a-zA-Z0-9-]+表示由字母、数字和减号组成的一个或多个字符;\.[a-zA-Z0-9-.]+表示一个点后面跟着由字母、数字、点和减号组成的一个或多个字符 。这个正则表达式模式能够准确地匹配常见的电子邮件地址格式 。

五、爬虫进阶技巧

5.1 处理反爬虫机制

在爬虫的征程中,我们常常会遭遇网站的反爬虫机制,这就如同在寻宝路上遇到了重重关卡 。不过别担心,我们有一系列有效的应对策略 。

设置请求头是一个简单而有效的方法。网站往往会通过检测请求头中的User - Agent等信息来判断请求是否来自爬虫 。我们可以通过模拟真实浏览器的请求头,让网站误以为是普通用户在访问 。例如,在Python的requests库中,可以这样设置请求头:

import requests

url = "https://example.com"

headers = {

      "User - Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"

}

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

这里的User - Agent字符串模拟了Chrome浏览器的信息,通过这种方式,可以增加请求的可信度 。

使用代理IP也是突破反爬虫限制的重要手段 。当我们的IP地址因为频繁请求被网站封禁时,代理IP就像是我们的“替身”,帮助我们继续访问网站 。可以使用一些免费或付费的代理IP服务,在Python中,通过requests库设置代理IP的示例如下:

import requests

url = "https://example.com"

proxies = {

      "http": "http://your\_proxy\_ip:your\_proxy\_port",

      "https": "https://your\_proxy\_ip:your\_proxy\_port"

}

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

在使用代理IP时,要注意选择可靠的代理源,确保代理IP的稳定性和可用性 。

此外,控制请求频率也至关重要 。如果短时间内向网站发送大量请求,很容易被识别为爬虫 。我们可以通过设置时间间隔,让请求更加“温柔” 。例如,使用time模块中的sleep函数,在每次请求后暂停一段时间:

import requests

import time

url\_list = \["https://example1.com", "https://example2.com", "https://example3.com"]

for url in url\_list:

      response = requests.get(url)

      time.sleep(5)  # 暂停5秒

这样,每隔5秒发送一次请求,降低了被反爬虫机制检测到的风险 。

5.2 动态网页抓取

随着网页技术的发展,越来越多的网页采用了动态加载技术,这给爬虫带来了新的挑战 。传统的直接获取HTML内容的方法,可能无法获取到动态加载的数据 。不过,我们有专门的工具来应对这一情况 。

Selenium是一个强大的自动化测试工具,它可以模拟真实用户在浏览器中的操作,从而获取动态网页的完整内容 。使用Selenium,首先需要安装对应的浏览器驱动,以Chrome浏览器为例,从ChromeDriver官网下载与浏览器版本匹配的驱动 。安装完成后,通过pip install selenium安装Selenium库 。以下是使用Selenium打开网页并获取内容的示例:

from selenium import webdriver

driver = webdriver.Chrome()

driver.get("https://example.com")

# 获取网页内容

page\_source = driver.page\_source

print(page\_source)

driver.quit()

在这个示例中,webdriver.Chrome()创建了一个Chrome浏览器驱动实例,driver.get(url)打开指定的网页,driver.page_source获取网页的源代码,最后driver.quit()关闭浏览器 。

除了Selenium,Scrapy - Splash也是一个不错的选择,它是Scrapy框架的一个插件,专门用于处理动态网页 。Splash是一个基于JavaScript渲染的服务,它可以在服务器端渲染JavaScript,然后将渲染后的HTML返回给爬虫 。使用Scrapy - Splash时,需要先安装Splash服务,并在Scrapy项目中进行相应的配置 。配置完成后,就可以在爬虫代码中使用Splash来处理动态网页了 。例如,在Scrapy的settings.py文件中添加如下配置:

SPLASH\_URL = 'http://localhost:8050'

DOWNLOADER\_MIDDLEWARES = {

    'scrapy\_splash.SplashDeduplicateArgsMiddleware': 100,

     'scrapy.downloader.middlewares.httpcompression.HttpCompressionMiddleware': 810,

    'scrapy\_splash.SplashMiddleware': 820,

}

SPIDER\_MIDDLEWARES = {

    'scrapy\_splash.SplashDeduplicateArgsMiddleware': 100,

    'scrapy\_splash.SplashDeduplicateArgsMiddleware': 100,

    'scrapy\_splash.SplashSpiderMiddleware': 725,

}

DUPEFILTER\_CLASS ='scrapy\_splash.SplashAwareDupeFilter'

HTTPCACHE\_STORAGE ='scrapy\_splash.SplashAwareFSCacheStorage'

然后在爬虫代码中使用Splash的Request对象发送请求:

from scrapy\_splash import SplashRequest

class MySpider(scrapy.Spider):

      name = "my\_spider"

      start\_urls = \["https://example.com"]

      def start\_requests(self):

          for url in self.start\_urls:

              yield SplashRequest(url, self.parse, args={'wait': 5})

      def parse(self, response):

          # 解析网页内容

          pass

在这个例子中,SplashRequest会将请求发送到Splash服务,args={'wait': 5}表示等待5秒,确保页面的JavaScript代码充分渲染后再获取内容 。

5.3 多线程与异步爬虫

在数据量较大的情况下,单线程爬虫的效率可能会比较低 。这时,我们可以利用多线程和异步编程技术来提高爬虫的效率 。

多线程爬虫可以同时开启多个线程,每个线程负责一个或多个URL的请求和数据提取工作,从而大大加快数据采集的速度 。在Python中,可以使用threading模块来实现多线程爬虫 。例如:

import threading

import requests

def fetch\_url(url):

      response = requests.get(url)

      print(response.text)

url\_list = \["https://example1.com", "https://example2.com", "https://example3.com"]

threads = \[]

for url in url\_list:

      t = threading.Thread(target = fetch\_url, args = (url,))

      threads.append(t)

      t.start()

for t in threads:

      t.join()

在这个代码中,threading.Thread(target = fetch_url, args = (url,))创建了一个新的线程,target指定线程要执行的函数,args传递函数所需的参数 。通过这种方式,多个线程同时对不同的URL发起请求,提高了爬虫的效率 。

异步爬虫则是利用Python的异步编程特性,在一个线程中实现非阻塞的I/O操作 。在等待网络请求的过程中,程序可以执行其他任务,从而避免了线程的阻塞,提高了资源的利用率 。asyncio是Python中用于异步编程的标准库,结合aiohttp库(用于异步HTTP请求),可以实现高效的异步爬虫 。示例代码如下:

import asyncio

import aiohttp

async def fetch\_url(session, url):

      async with session.get(url) as response:

          return await response.text()

async def main():

      urls = \["https://example1.com", "https://example2.com", "https://example3.com"]

      async with aiohttp.ClientSession() as session:

          tasks = \[fetch\_url(session, url) for url in urls]

          results = await asyncio.gather(\*tasks)

          for result in results:

              print(result)

if \_\_name\_\_ == "\_\_main\_\_":

      asyncio.run(main())

在这个例子中,async def定义了异步函数,await用于等待异步操作的完成 。aiohttp.ClientSession()创建了一个HTTP会话,tasks列表包含了所有的异步任务,asyncio.gather(*tasks)用于并行运行这些任务,并等待所有任务完成 。通过这种方式,实现了高效的异步爬虫 。

六、爬虫框架应用

6.1 Scrapy框架

Scrapy是一款强大且广泛应用的Python爬虫框架 ,它为爬虫开发提供了高效、便捷的解决方案 。

Scrapy的架构犹如一个精密的机器,由多个核心组件协同工作 。其中,引擎(Engine)是整个框架的核心枢纽,负责协调各个组件之间的通信和数据流动 。它从调度器(Scheduler)获取待爬取的URL,将请求发送给下载器(Downloader),下载器从网络上下载网页内容后,再将响应返回给引擎,引擎又将响应传递给爬虫(Spider)进行数据解析 。而管道(Pipeline)则负责处理爬虫提取的数据,进行数据的清洗、存储等操作 。调度器就像是一个智能的任务分配器,它维护着一个URL队列,负责管理和调度待爬取的URL,确保每个URL都能被合理地安排爬取顺序,同时还能对重复的URL进行去重处理 。

在使用Scrapy框架时,首先需要创建一个Scrapy项目 。通过在命令行中输入scrapy startproject 项目名称,即可快速创建一个项目框架 。例如,创建一个名为my_crawler的项目,命令如下:

scrapy startproject my\_crawler

进入项目目录后,可以使用scrapy genspider 爬虫名称 目标域名命令创建一个爬虫 。假设要爬取example.com网站的数据,创建爬虫的命令如下:

cd my\_crawler

scrapy genspider example\_spider example.com

在生成的爬虫文件中,需要定义爬虫的逻辑 。例如,以下是一个简单的爬虫示例,用于爬取指定网页上的标题信息:

import scrapy

class ExampleSpider(scrapy.Spider):

      name = "example\_spider"

      allowed\_domains = \["example.com"]

      start\_urls = \["https://example.com"]

      def parse(self, response):

          titles = response.css('title::text').extract()

          for title in titles:

              yield {'title': title}

在这个例子中,parse方法是爬虫的核心逻辑部分,它使用CSS选择器提取网页中的标题信息,并通过yield将数据传递给管道进行后续处理 。

6.2 PySpider框架

PySpider是一个轻量级且功能强大的爬虫框架,它具有独特的特点和适用场景 。

PySpider的一大亮点是其提供了直观易用的WebUI界面 。通过这个界面,开发者可以方便地进行项目管理、任务监控以及结果查看 。在WebUI中,你可以轻松地创建、编辑和启动爬虫任务,实时了解爬虫的运行状态,查看爬取到的数据结果,这大大提高了开发和调试的效率 。

PySpider支持多种数据存储方式,包括MySQL、MongoDB、Redis等常见数据库 。这使得开发者可以根据项目的实际需求,灵活选择最适合的数据存储方案,方便后续的数据处理和分析 。

它还具备强大的分布式爬虫能力 。通过配置多个爬虫节点,PySpider可以实现高并发的爬取任务,显著提高数据采集的速度和效率 。这一特性使得它在处理大规模数据爬取任务时表现出色 。

例如,使用PySpider爬取一个新闻网站的文章内容 。首先,安装PySpider,可以通过pip install pyspider命令进行安装 。安装完成后,启动PySpider服务,输入pyspider all命令 。在浏览器中访问http://localhost:5000,进入PySpider的WebUI界面 。在WebUI中创建一个新的爬虫项目,编写如下爬虫代码:

from pyspider.libs.base\_handler import \*

class NewsSpider(BaseHandler):

      crawl\_config = {}

      @every(minutes=24 \* 60)

      def on\_start(self):

          self.crawl('https://news.example.com', callback=self.index\_page)

      def index\_page(self, response):

          for each in response.doc('a\[href^="http"]').items():

              self.crawl(each.attr.href, callback=self.detail\_page)

      def detail\_page(self, response):

          title = response.doc('title').text()

          content = response.doc('.article-content').text()

          return {'title': title, 'content': content}

在这个例子中,on_start方法定义了爬虫的起始URL,index_page方法用于解析列表页,提取文章链接并交给detail_page方法进行详情页的解析,最终提取出文章的标题和内容 。通过PySpider的WebUI界面,我们可以方便地启动、监控和管理这个爬虫任务 。

七、实战项目演练

7.1 小型爬虫项目

为了让大家更直观地感受爬虫的魅力,我们以爬取豆瓣电影Top250为例,展示一个完整的爬虫实现过程 。豆瓣电影Top250是电影爱好者们关注的热门榜单,其中包含了丰富的电影信息 。

首先,我们需要分析网页结构。通过浏览器的开发者工具(如Chrome浏览器的F12快捷键),可以查看网页的HTML源代码,找到电影信息所在的标签和属性 。例如,电影标题通常在<span class="title">标签内,评分在<span class="rating_num">标签内 。

接下来,编写爬虫代码。使用Python的requests库和BeautifulSoup库,代码如下:

import requests

from bs4 import BeautifulSoup

import csv

def get\_movie\_info(url):

      headers = {

          "User - Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"

      }

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

      if response.status\_code == 200:

          soup = BeautifulSoup(response.text, 'html.parser')

          movie\_list = soup.find\_all('div', class\_='item')

          for movie in movie\_list:

              title = movie.find('span', class\_='title').text

              rating = movie.find('span', class\_='rating\_num').text

              quote = movie.find('span', class\_='inq')

              quote = quote.text if quote else '无'

              yield {

                  'title': title,

                  'rating': rating,

                  'quote': quote

              }

      else:

          print(f"请求失败,状态码: {response.status\_code}")

def save\_to\_csv(data, filename='douban\_movies.csv'):

      with open(filename, 'w', newline='', encoding='utf - 8') as csvfile:

          fieldnames = \['title', 'rating', 'quote']

          writer = csv.DictWriter(csvfile, fieldnames = fieldnames)

          writer.writeheader()

          for movie in data:

              writer.writerow(movie)

if \_\_name\_\_ == "\_\_main\_\_":

      base\_url = "https://movie.douban.com/top250?start={}\&filter="

      all\_movie\_info = \[]

      for start in range(0, 250, 25):

          url = base\_url.format(start)

          movie\_info = get\_movie\_info(url)

          all\_movie\_info.extend(movie\_info)

      save\_to\_csv(all\_movie\_info)

在这段代码中,get_movie_info函数负责发送请求、解析网页并提取电影的标题、评分和简介信息 。save_to_csv函数将提取到的数据保存为CSV文件 。通过循环遍历不同的页码,我们可以获取到豆瓣电影Top250的所有信息 。

7.2 大型综合爬虫项目

现在,我们迈向一个更具挑战性的任务——爬取电商平台的商品信息,并实现数据持久化和分布式爬虫功能 。以爬取某电商平台的手机商品信息为例,这一过程涉及多个复杂的环节 。

首先,我们要解决反爬虫问题。电商平台通常具有严格的反爬虫机制,我们可以通过设置请求头、使用代理IP等方式来伪装请求 。同时,为了实现数据持久化,我们选择将数据存储到MySQL数据库中 。以下是使用Scrapy框架实现的部分代码示例:

import scrapy

import pymysql

class MobileSpider(scrapy.Spider):

      name = "mobile\_spider"

      allowed\_domains = \["example.com"]

      start\_urls = \["https://example.com/mobiles"]

      def parse(self, response):

          for mobile in response.css('.mobile-item'):

              item = {

                  'title': mobile.css('.title::text').get(),

                  'price': mobile.css('.price::text').get(),

                  'rating': mobile.css('.rating::text').get()

              }

              yield item

          next\_page = response.css('.next-page::attr(href)').get()

          if next\_page:

              yield response.follow(next\_page, self.parse)

class MySQLPipeline:

      def \_\_init\_\_(self):

          self.conn = pymysql.connect(

              host='localhost',

              user='root',

              password='password',

              db='ecommerce',

              charset='utf8'

          )

          self.cursor = self.conn.cursor()

      def process\_item(self, item, spider):

          sql = "INSERT INTO mobiles (title, price, rating) VALUES (%s, %s, %s)"

          values = (item\['title'], item\['price'], item\['rating'])

          self.cursor.execute(sql, values)

          self.conn.commit()

          return item

      def close\_spider(self, spider):

          self.cursor.close()

          self.conn.close()

在这个代码中,MobileSpider类定义了爬虫的逻辑,包括起始URL、数据解析和分页处理 。MySQLPipeline类负责将爬取到的数据插入到MySQL数据库的mobiles表中 。

对于分布式爬虫,我们可以借助Scrapy - Redis框架来实现 。Scrapy - Redis能够将爬取任务分配到多个节点上并行执行,大大提高爬取效率 。首先,需要安装Scrapy - Redis库,通过pip install scrapy - redis命令进行安装 。然后,在settings.py文件中进行如下配置:

# 启用Redis调度存储请求队列

SCHEDULER = "scrapy\_redis.scheduler.Scheduler"

# 确保所有爬虫共享相同的去重指纹

DUPEFILTER\_CLASS = "scrapy\_redis.dupefilter.RFPDupeFilter"

# Redis连接设置

REDIS\_HOST = 'localhost'

REDIS\_PORT = 6379

在爬虫类中,继承RedisSpider类,如下所示:

from scrapy\_redis.spiders import RedisSpider

class DistributedMobileSpider(RedisSpider):

      name = "distributed\_mobile\_spider"

      redis\_key = "mobile:start\_urls"

      def parse(self, response):

          # 解析逻辑与普通Spider类似

          pass

在这个配置中,redis_key指定了Redis中存储起始URL的键 。通过将起始URL放入Redis队列中,不同的爬虫节点可以从队列中获取任务并进行处理,从而实现分布式爬取 。

八、总结与展望

在本次爬虫之旅中,我们从基础语法出发,逐步深入到爬虫的核心原理、常用库、进阶技巧、框架应用以及实战项目 。通过学习,我们掌握了如何利用Python语言搭建爬虫环境,使用各种库和工具来发送HTTP请求、解析网页数据、处理反爬虫机制以及实现高效的数据采集 。同时,我们还了解了不同爬虫框架的特点和优势,以及如何将其应用于实际项目中 。

展望未来,爬虫技术将随着互联网的发展而不断演进 。随着大数据和人工智能技术的蓬勃发展,爬虫技术有望在数据采集和分析方面发挥更为关键的作用 。未来,爬虫可能会更加智能化,能够自动识别网页结构的变化,灵活调整抓取策略,从而提高数据采集的准确性和效率 。同时,在分布式爬虫领域,随着技术的不断完善,多节点协作的效率将进一步提升,能够更快地处理大规模的数据爬取任务 。此外,随着数据安全和隐私保护意识的不断增强,爬虫技术也将更加注重合规性和安全性,确保在合法、安全的前提下进行数据采集 。

爬虫技术的发展前景广阔,充满了无限的可能性 。希望大家在今后的学习和实践中,能够不断探索和创新,充分发挥爬虫技术的优势,为各个领域的发展贡献自己的力量 。

Loading comments...