第三章——爬虫工具场景之Python爬虫实战:行业资讯爬取与存储,抢占信息先机

在当今瞬息万变的商业环境和个人发展进程中,及时掌握行业资讯犹如握住开启成功之门的钥匙。对于企业而言,行业资讯是制定战略决策、把握市场趋势、洞察竞争对手动态的重要依据;对于个人来说,它有助于明确职业发展方向、提升自身竞争力。本部分将深入讲解如何利用Python实现行业资讯的爬取与存储,助力你在信息浪潮中抢占先机。

一、课程引入:及时获取行业资讯的重要性

在数字化时代,信息传播速度极快,行业动态瞬息万变。例如,科技行业的新兴技术突破可能瞬间改变市场格局,传统制造业的原材料价格波动会直接影响生产成本和产品定价。企业若能及时获取这些资讯,就能提前布局,调整生产策略、优化产品研发方向,在竞争中脱颖而出。对于个人,如求职者了解行业前沿趋势和人才需求变化,可针对性地提升技能,增加就业竞争力。因此,掌握快速获取行业资讯的方法迫在眉睫。

二、需求分析

我们的目标很明确,输入行业资讯网站的URL,通过编写爬虫程序,获取网站上的资讯内容,并将其存储起来,方便后续随时查阅和分析。无论是专业的行业资讯网站,还是综合新闻平台中的行业板块,都要能实现精准爬取与有效存储。

三、核心功能拆解

  1. 网页请求发送:向指定的行业资讯网站发送HTTP请求,这就像是向网站"敲门",请求获取网页内容。
  2. 网页解析:将获取到的网页原始内容进行解析,把复杂的HTML代码转化为计算机易于理解和处理的结构,为后续提取数据做准备。
  3. 数据提取:从解析后的网页结构中,准确地定位并提取出我们关注的资讯标题、正文等关键内容。
  4. 数据存储:把提取到的资讯内容存储到文件(如CSV)或数据库中,实现数据的长期保存与便捷检索。

四、代码分步实现

导入requestsBeautifulSoup库,讲解库的功能

在Python爬虫开发中,requests库和BeautifulSoup库是两个强大的工具。

python 复制代码
import requests
from bs4 import BeautifulSoup
  • requests库:主要用于发送HTTP请求,获取网页内容。它提供了简洁易用的接口,可以轻松模拟浏览器发送各种类型的请求(如GET、POST等),并处理响应。例如,我们可以使用它获取网页的HTML文本、图片、文件等资源。
  • BeautifulSoup库:用于解析HTML或XML文档。它能够将复杂的网页结构转化为树形结构,方便我们通过各种选择器来定位和提取所需的数据。例如,通过标签名、类名、ID等方式找到特定的HTML元素,并获取其文本内容、属性值等。

发送HTTP请求获取网页内容,注释请求头设置意义

使用requests库发送HTTP GET请求获取网页内容。同时,合理设置请求头可以模拟浏览器行为,避免被网站识别为爬虫而拒绝访问。

python 复制代码
url = 'https://example.com'  # 替换为实际的行业资讯网站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:
    html_content = response.text
else:
    print(f'请求失败,状态码: {response.status_code}')
  • url:指定要爬取的行业资讯网站的URL。
  • headers:设置请求头,其中User - Agent模拟了一个常见的浏览器标识。网站通常会根据User - Agent来判断请求是否来自真实浏览器。通过设置合理的User - Agent,可以增加爬虫的伪装性,降低被反爬机制拦截的风险。
  • requests.get(url, headers = headers):发送HTTP GET请求到指定的url,并带上设置的请求头headers
  • response.status_code:获取响应的状态码,200表示请求成功,其他状态码可能表示不同的错误情况。若请求成功,将网页的文本内容赋值给html_content

使用BeautifulSoup解析网页,讲解HTML结构分析

获取到网页内容后,使用BeautifulSoup进行解析。首先要了解HTML的基本结构,HTML文档由一系列的标签组成,如<html><head><body>等,标签可以嵌套形成树形结构。

python 复制代码
soup = BeautifulSoup(html_content, 'html.parser')

这里使用html.parser解析器来解析html_content,创建一个BeautifulSoup对象soupBeautifulSoup会将HTML内容解析成一个树形结构,我们可以通过遍历这个树形结构来定位和提取数据。例如,soup.body可以获取HTML文档的<body>部分,soup.find_all('a')可以找到所有的<a>标签(链接标签)。

定位并提取资讯标题、正文等内容,注释选择器使用方法

通过分析网页的HTML结构,使用BeautifulSoup的选择器来定位和提取资讯标题、正文等内容。假设资讯标题在<h1>标签中,正文在<div>标签且该div具有特定的类名article - content

python 复制代码
# 提取标题
title = soup.find('h1').text if soup.find('h1') else '未找到标题'

# 提取正文
article_content = soup.find('div', class_='article - content')
content = article_content.get_text() if article_content else '未找到正文'
  • soup.find('h1'):使用find方法查找第一个<h1>标签,若找到则通过.text获取其文本内容作为标题;若未找到则返回"未找到标题"。
  • soup.find('div', class_='article - content'):使用find方法查找具有article - content类名的<div>标签,这是定位正文所在的标签。class_中的下划线是因为class是Python的关键字,所以在BeautifulSoup中使用class_来表示HTML中的class属性。若找到该标签,通过.get_text()获取其文本内容作为正文;若未找到则返回"未找到正文"。

将提取的数据存储到文件(如CSV)或数据库,讲解存储操作

存储到CSV文件

CSV(Comma - Separated Values)是一种常用的文件格式,用于存储表格数据。使用Python的csv模块可以方便地将数据存储为CSV文件。

python 复制代码
import csv

with open('industry_news.csv', 'w', newline='', encoding='utf - 8') as csvfile:
    fieldnames = ['标题', '正文']
    writer = csv.DictWriter(csvfile, fieldnames = fieldnames)
    writer.writeheader()
    writer.writerow({'标题': title, '正文': content})
  • open('industry_news.csv', 'w', newline='', encoding='utf - 8'):以写入模式打开一个名为industry_news.csv的文件,newline=''用于避免在Windows系统下写入CSV文件时出现额外的空行,encoding='utf - 8'指定文件编码为UTF - 8,以支持各种字符。
  • fieldnames定义了CSV文件的表头。
  • csv.DictWriter(csvfile, fieldnames = fieldnames)创建一个DictWriter对象,用于将字典形式的数据写入CSV文件。
  • writer.writeheader()写入表头。
  • writer.writerow({'标题': title, '正文': content})将提取到的标题和正文数据以字典形式写入CSV文件的一行。
存储到数据库(以SQLite为例)

SQLite是一种轻量级的数据库,适合小型项目和快速开发。首先需要导入sqlite3模块。

python 复制代码
import sqlite3

conn = sqlite3.connect('industry_news.db')
cursor = conn.cursor()

cursor.execute('''CREATE TABLE IF NOT EXISTS news (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    title TEXT,
                    content TEXT
                )''')

cursor.execute("INSERT INTO news (title, content) VALUES (?,?)", (title, content))
conn.commit()
conn.close()
  • sqlite3.connect('industry_news.db'):连接到名为industry_news.db的SQLite数据库,如果数据库不存在则创建。
  • cursor.execute('''CREATE TABLE IF NOT EXISTS news...'''):创建一个名为news的表(如果不存在),表中包含id(自增主键)、title(标题)和content(正文)字段。
  • cursor.execute("INSERT INTO news (title, content) VALUES (?,?)", (title, content)):将提取到的标题和正文数据插入到news表中。
  • conn.commit():提交事务,确保数据插入操作生效。
  • conn.close():关闭数据库连接。

五、优化迭代:提高爬取效率,处理动态加载网页

提高爬取效率

为提高爬取效率,可以采用多线程或异步编程方式。例如,使用concurrent.futures模块实现多线程爬取多个网页。假设有一个包含多个URL的列表urls

python 复制代码
import concurrent.futures

def crawl(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:
        html_content = response.text
        soup = BeautifulSoup(html_content, 'html.parser')
        title = soup.find('h1').text if soup.find('h1') else '未找到标题'
        article_content = soup.find('div', class_='article - content')
        content = article_content.get_text() if article_content else '未找到正文'
        return {'标题': title, '正文': content}
    else:
        return {'标题': f'请求失败,状态码: {response.status_code}', '正文': ''}

with concurrent.futures.ThreadPoolExecutor() as executor:
    results = list(executor.map(crawl, urls))

for result in results:
    print(result)

上述代码定义了一个crawl函数用于爬取单个URL的内容,通过ThreadPoolExecutor创建线程池,使用executor.map方法并行调用crawl函数处理多个URL,从而提高爬取效率。

处理动态加载网页

许多现代网站采用动态加载技术,即部分内容通过JavaScript在页面加载后异步获取。对于这类网页,可以使用Selenium库结合浏览器驱动(如ChromeDriver)来模拟浏览器行为,等待页面动态内容加载完成后再进行数据提取。

python 复制代码
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome()
driver.get(url)

try:
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.CLASS_NAME, 'article - content'))
    )
    html_content = driver.page_source
    soup = BeautifulSoup(html_content, 'html.parser')
    title = soup.find('h1').text if soup.find('h1') else '未找到标题'
    content = soup.find('div', class_='article - content').get_text() if soup.find('div', class_='article - content') else '未找到正文'
finally:
    driver.quit()

上述代码使用Selenium打开指定的URL,通过WebDriverWait等待具有article - content类名的元素出现(最多等待10秒),这确保了动态内容已加载完成。然后获取页面源代码,使用BeautifulSoup进行解析和数据提取,最后关闭浏览器驱动。

六、部署测试:定期运行爬虫测试数据更新情况

将爬虫程序部署到服务器上(如阿里云、腾讯云等),可以使用crontab(Linux系统)或任务计划程序(Windows系统)来定期运行爬虫。例如,在Linux系统中,使用以下命令编辑crontab文件,设置每天凌晨2点运行爬虫:

sh 复制代码
0 2 * * * python /path/to/your/crawler.py

每次运行爬虫后,检查存储的数据文件或数据库,查看是否成功获取到新的行业资讯,对比新旧数据,确保数据的更新情况符合预期。同时,记录爬虫运行过程中的日志信息,方便排查可能出现的问题。

七、问题排查:解决反爬机制应对(如IP封禁、验证码处理)、网页结构变化导致的提取失败问题

应对反爬机制

  1. IP封禁 :如果IP被封禁,可以采用IP代理池的方式。收集一些免费或付费的代理IP,在每次请求时随机选择一个代理IP。例如,使用requests库结合proxies参数设置代理:
python 复制代码
proxies = {
    'http': 'http://your_proxy_ip:port',
    'https': 'https://your_proxy_ip:port'
}
response = requests.get(url, headers = headers, proxies = proxies)
  1. 验证码处理 :对于简单的验证码(如数字验证码),可以使用pytesseract库结合PIL(Python Imaging Library)进行识别。首先安装相关库:
sh 复制代码
pip install pytesseract pillow

假设验证码图片的元素ID为captcha - img,可以使用以下代码获取并识别验证码:

python 复制代码
from selenium import webdriver
from PIL import Image
import pytesseract

driver = webdriver.Chrome()
driver.get(url)

captcha_image = driver.find_element(By.ID, 'captcha - img')
captcha_image.screenshot('captcha.png')

image = Image.open('captcha.png')
captcha_text = pytesseract.image_to_string(image)
print(captcha_text)

对于复杂的验证码(如滑块验证码、拼图验证码等),可能需要使用第三方打码平台(如超级鹰)来识别。

网页结构变化

网页结构变化是爬虫面临的常见问题。可以定期检查网页结构,当发现提取失败时,重新分析网页的HTML结构,更新选择器。同时,可以使用版本控制系统(如Git)来记录爬虫代码的变化,便于回溯和管理。

完整举例代码

以下是一个完整的示例代码,整合了上述所有功能,包括基本的爬取、存储、多线程优化以及简单的反爬处理(设置请求头和使用代理):

python 复制代码
import requests
from bs4 import BeautifulSoup
import csv
import sqlite3
import concurrent.futures
import random


def crawl(url, proxy=None):
    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'
    }
    try:
        if proxy:
            response = requests.get(url, headers=headers, proxies=proxy)
        else:
            response = requests.get(url, headers=headers)
        if response.status_code == 200:
            html_content = response.text
            soup = BeautifulSoup(html_content, 'html.parser')
            title = soup.find('h1').text if soup.find('h1') else '未找到标题'
            article_content = soup.find('div', class_='article - content')
            content = article_content.get_text() if article_content else '未找到正文'
            return {'标题': title, '正文': content}
        else:
            return {'标题': f'请求失败,状态码: {response.status_code}', '正文': ''}
    except Exception as e:
        return {'标题': f'发生错误: {str(e)}', '正文': ''}


def save_to_csv(data, filename='industry_news.csv'):
    with open(filename, 'w', newline='', encoding='utf - 8') as csvfile:
        fieldnames = ['标题', '正文']
        writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
        writer.writeheader()
        for item in data:
            writer.writerow(item)


def save_to_sqlite(data, db_name='industry_news.db'):
    conn = sqlite3.connect(db_name)
    cursor = conn.cursor()
    cursor.execute('''CREATE TABLE IF NOT EXISTS news (
                        id INTEGER PRIMARY KEY AUTOINCREMENT,
                        title TEXT,
                        content TEXT
                    )''')
    for item in data:
        cursor.execute("INSERT INTO news (title, content) VALUES (?,?)", (item['标题'], item['正文']))
    conn.commit()
    conn.close()


if __name__ == '__main__':
    urls = ['https://example1.com', 'https://example2.com']  # 替换为实际的URL列表
    proxies = [
        {'http': 'http://proxy1_ip:port', 'https': 'https://proxy1_ip:port'},
        {'http': 'http://proxy2_ip:port', 'https': 'https://proxy2_ip:port'}
    ]
    with concurrent
if __name__ == '__main__':
    urls = ['https://example1.com', 'https://example2.com']  # 替换为实际的URL列表
    proxies = [
        {'http': 'http://proxy1_ip:port', 'https': 'https://proxy1_ip:port'},
        {'http': 'http://proxy2_ip:port', 'https': 'https://proxy2_ip:port'}
    ]
    with concurrent.futures.ThreadPoolExecutor() as executor:
        results = list(executor.map(lambda u: crawl(u, random.choice(proxies) if proxies else None), urls))

    save_to_csv(results)
    save_to_sqlite(results)

代码说明

  1. crawl函数:负责发送HTTP请求,获取网页内容并解析提取标题和正文。如果提供了代理,就使用代理发送请求,在请求成功时返回提取的数据,失败或出错时返回错误信息。
  2. save_to_csv函数 :将爬取到的数据保存为CSV文件,文件名为industry_news.csv,并设置合适的编码和表头。
  3. save_to_sqlite函数 :把数据保存到SQLite数据库industry_news.db中,若数据库不存在则创建,并创建名为news的表用于存储标题和正文。
  4. 主程序部分 :定义了一个URL列表,代表要爬取的多个行业资讯网页地址。同时定义了一个代理列表(这里只是示例,需替换为真实有效的代理)。通过线程池并发调用crawl函数爬取每个URL的内容,随机选择代理进行请求。最后,将爬取结果分别保存到CSV文件和SQLite数据库中。

通过以上完整的代码示例,你可以更直观地看到如何将行业资讯爬取与存储的各个功能整合在一起,实现一个较为完整的爬虫程序。当然,在实际应用中,你需要根据具体的网站结构和反爬机制对代码进行调整和优化。

相关推荐
Pyeako2 小时前
网络爬虫相关操作--selenium库(超详细版)
爬虫·python·selenium
dagouaofei2 小时前
全面整理6款文档生成PPT工具,PDF转PPT不再难
python·pdf·powerpoint
β添砖java2 小时前
python第一阶段第10章
开发语言·python
伊玛目的门徒2 小时前
HTTP SSE 流式响应处理:调用腾讯 智能应用开发平台ADP智能体的 API
python·网络协议·http·腾讯智能体·adp·智能应用开发平台
倔强的小石头_2 小时前
Python 从入门到实战(八):类(面向对象的 “对象模板”)
服务器·开发语言·python
Mr_Xuhhh2 小时前
第一部分:类和对象(中)— 取地址运算符重载
java·开发语言
Selegant2 小时前
告别传统部署:用 GraalVM Native Image 构建秒级启动的 Java 微服务
java·开发语言·微服务·云原生·架构
qq_214782613 小时前
GWalkR,部分替代Tableau!
ide·python·jupyter
Liii4033 小时前
Java集合详细讲解
java·开发语言