数据采集基础:爬虫基本原理、Requests库入门、BeautifulSoup解析HTML

各位同学好,今天我们来聊聊数据采集这块硬骨头。做舆情监控,说白了第一步就是「怎么把数据拿回来」。我刚开始接触爬虫那会儿,总觉得这东西很神秘,后来发现,其实就是模拟浏览器去访问网页,然后把内容拆开、提取、存起来。嗯,就这么简单。

核心一句话:爬虫 = 模拟请求 + 解析响应 + 提取数据。

爬虫的基本原理

爬虫的本质是什么?你想想看,你在浏览器里输入网址,回车,页面出来了。爬虫做的就是这件事——只不过是用代码代替了鼠标和键盘。

一个完整的爬虫流程,我习惯把它拆成三步:

  1. 发送请求:用代码向目标服务器说「嘿,把页面给我」。
  2. 获取响应:服务器返回HTML、JSON或者别的格式数据。
  3. 解析提取:从返回的数据里,把我们想要的信息抠出来。

我在项目中遇到过一个问题:有些网站会检测你是不是真人。比如频繁请求会被封IP,或者需要处理Cookie。这些坑,后面我会一个个说。

注意:爬虫不是万能的。有些网站有反爬机制,比如验证码、IP限制、User-Agent检测。做舆情监控,一定要遵守网站的robots.txt协议,别把自己搞进黑名单。

下面这张图,是我自己总结的爬虫核心流程,你一看就明白:

目标URL 发送请求 获取响应 解析HTML 提取数据 存储数据 循环翻页

Requests库入门

Python里做网络请求,Requests库是首选。为什么?因为它够简单、够直观。我最早用urllib的时候,写个POST请求要好几行,换了Requests之后,一行搞定。

先安装:

pip install requests

然后看个最简单的例子——拿百度首页:

import requests

url = "https://www.baidu.com"
response = requests.get(url)

print(response.status_code)  # 200 表示成功
print(response.text[:500])   # 打印前500个字符

跑一下,你会看到一堆HTML代码。这就是服务器给你的原始响应。

小技巧:我习惯在请求时加个headers参数,模拟浏览器访问。不然有些网站直接返回403。

加headers的写法:

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
response = requests.get(url, headers=headers)

为什么会这样?因为服务器会检查请求头,如果发现你是「爬虫」,直接拒绝。加个常见的浏览器User-Agent,就能蒙混过关。

Requests还支持POST、PUT、DELETE等方法。做舆情监控,最常用的是GET和POST。比如模拟登录时,就得用POST提交表单数据:

data = {"username": "admin", "password": "123456"}
response = requests.post("https://example.com/login", data=data)

我曾经踩过一个坑:某个网站返回的数据是压缩过的,直接打印出来全是乱码。后来发现加个 response.encoding = 'utf-8' 就解决了。嗯,这里要注意,有时候服务器返回的编码和页面实际编码不一致,手动指定一下更稳妥。

BeautifulSoup解析HTML

拿到HTML之后,怎么把我们需要的信息提取出来?手动正则匹配?太累了,而且容易出错。BeautifulSoup就是干这个的——把HTML变成一棵树,然后按标签、类名、ID去摘叶子。

安装:

pip install beautifulsoup4

基本用法:

from bs4 import BeautifulSoup

html = "<html><body><h1>Hello World</h1><p class='content'>这是正文</p></body></html>"
soup = BeautifulSoup(html, 'html.parser')

# 提取h1标签
h1 = soup.find('h1')
print(h1.text)  # 输出:Hello World

# 提取class为content的p标签
p = soup.find('p', class_='content')
print(p.text)  # 输出:这是正文

你看,就这么简单。find()返回第一个匹配的标签,find_all()返回所有匹配的列表。

实际项目中,我经常这样用:

# 假设我们要爬取新闻标题
news_list = soup.find_all('h2', class_='news-title')
for news in news_list:
    title = news.text.strip()
    link = news.find('a')['href']
    print(f"标题:{title},链接:{link}")

重点:BeautifulSoup支持多种解析器。默认的html.parser够用,但遇到复杂HTML时,我推荐用lxml,速度更快、容错性更好。

安装lxml:

pip install lxml

使用时改成:

soup = BeautifulSoup(html, 'lxml')

BeautifulSoup还支持CSS选择器,这个我特别喜欢。比如:

# 用CSS选择器提取所有class为item的div
items = soup.select('div.item')
for item in items:
    print(item.text)

我个人习惯是:简单的用find/find_all,复杂的用select。你想想看,如果嵌套层级很深,写一串find链式调用多累,CSS选择器一行搞定。

实战:爬取一个简单的新闻列表

光说不练假把式。我们拿一个真实的例子来演示——假设要爬取某个新闻网站的头条列表。

import requests
from bs4 import BeautifulSoup

url = "https://example-news.com"
headers = {"User-Agent": "Mozilla/5.0"}
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.text, 'lxml')

# 假设头条新闻都在class为headline的div里
headlines = soup.select('div.headline h2 a')
for headline in headlines:
    title = headline.text.strip()
    link = headline['href']
    print(f"{title} -> {link}")

跑完这段代码,你就能拿到所有头条的标题和链接。这就是舆情监控的第一步——把数据从网页上「薅」下来。

避坑指南:我曾经遇到过一个网站,它的HTML结构会动态变化。今天用class="title",明天改成class="heading"。解决方案是:不要死磕一个选择器,多观察页面结构,或者用更通用的匹配规则。

总结一下

今天的内容,说白了就是三件事:

  • 爬虫原理:请求-响应-解析,循环翻页。
  • Requests库:发请求、拿响应、加headers伪装。
  • BeautifulSoup:解析HTML、提取数据、用选择器定位。

这些是数据采集的基石。后面我们会讲更高级的东西,比如处理动态页面、应对反爬、分布式采集等等。但今天这些,你必须练熟。

嗯,回去之后自己动手写个爬虫,爬一下你常看的新闻网站。遇到问题很正常,多调试几次就通了。


专注资料整理