Contents

爬虫整理

网络基础概述

HTTP 协议

HyperText Transfer Protocol,超文本传输协议,是浏览器与服务器的文本交互协议

  • HTTP 请求报文方式
    GET:请求指定的页面信息
    POST:向指定资源 提交数据 进行处理请求

  • HTTP 常见状态码

    状态码 含义
    200 请求成功
    301 资源(网页等)被永久转移到其它 URL
    400 请求错误
    403 禁止访问
    404 请求的资源(网页等)不存在
    500 内部服务器错误

HTTPS 协议

基于 HTTP 协议,是 HTTP 的安全形式,HTTPS 网站是通过 SSL/TLS 加密流量的网站

要升级 https 协议,需要到 CA 进行认证,它会生成并颁发 SSL 证书
免费证书较少,所以通常需要一定费用

CA(Certificate Authority)
颁发数字证书的机构

了解 HTML 和 CSS

HTML 定义页面结构,CSS 负责样式渲染。了解标签层级与选择器是解析页面的前提

爬取核心技术栈

请求头(Headers)— 伪装浏览器

一些网站为了防止爬虫,会有一些检查机制
我们需要添加请求头 header,将 Python 伪装成浏览器
例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
headers = {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    "Accept-Encoding": "gzip, deflate",
    "Accept-Language": "zh-CN,zh;q=0.9",
    "Cache-Control": "max-age=0",
    "Connection": "keep-alive",
    "Host": "example.com",
    "Referer": "https://example.com",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/108.0.0.0 Safari/537.36"
}

requests 基础示例

1
2
3
4
5
6
7
8
import re, requests

resp = requests.get(url, headers=headers, timeout=10)
print("HTTP 状态码:", resp.status_code)

# 正则提取示例(根据实际页面结构调整)
title = re.search(r'<h1[^>]*>(.*?)</h1>', resp.text).group(1)
playinfo = re.search(r'window.__playinfo__\s*=\s*(\{.*?\});', resp.text).group(1)

BeautifulSoup(HTML 解析)

BeautifulSoup 是 HTML 解析库之一
其中 lxml,优点是处理速度快
而 html.parser 是自带的,不用安装比较方便

  • 假设要获取到标签 <div class="col-md-1"> 中的内容

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    import requests
    from bs4 import BeautifulSoup
    
    
    response = requests.get(url, headers=headers)
    # 通过美味汤解析响应的文本内容,并寻找对应 class 的 div 标签
    rows = BeautifulSoup(response.text, 'lxml').find_all(
        name = 'div',
        attrs = {'class': 'col-md-1'}
    )
    print(rows)    # 返回一个列表
    

    soup.find().get_text() 只返回第一个匹配到的对象

    可以将获取到的数据先存储为列表,之后再转为 pd.DataFrame
    再转为表格文件 df.to_excel(filename, index=False, encoding='utf-8')

  • 子节点、兄弟节点

    1
    2
    3
    4
    5
    6
    7
    
    # 打印 table 标签且 id 等于 giftList 下的子节点
    response = requests.get(url, headers=headers)
    bsObj = BeautifulSoup(response.text, 'html.parser')
    
    for child in bsObj.find("table", {"id": "giftList"}).children:
        print(child)
    # 同理有处理父标签的方法 .parent
    
    1
    2
    3
    
    # 获取 table#giftList -> tr 的后一兄弟标签
    bsObj.find("table", {"id": "giftList"}).tr.next_siblings
    # 同理有 previous_siblings() 获取前一兄弟标签
    
  • 获取标签的属性

    1
    2
    
    # .attrs 返回一个字典
    Tag.attrs["src"]
    

JSON 数据

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import json


# loads 方法可以理解为
# 字符串类型 转为 字典
# 注意里面的键值用的是【双引号】
json_data = '{"name": "Mike", "age": "30"}'
dict_data = json.loads(json_data)


# dumps 方法可以理解为
# 字典 转为 字符串类型
dict_data = {"name": "Mike", "age": "30"}
json_data = json.dumps(dict_data, ensure_ascii=False, indent=2)

动态内容获取

selenium 可以模拟浏览器行为

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 模块导入
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver import ActionChains

import pyautogui
from lxml import html


# driver 的路径
DRIVER_PATH = "D:/python/msedgedriver.exe"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
driver = webdriver.Edge(DRIVER_PATH)

# 最大化窗口
driver.maximize_window()
# 自定义窗口大小
driver.set_window_size(1280, 720)

# 设置等待时间
# 设置最长等待时间为 20 秒,且每 1 秒就检测一下网页是否加载完全
wait = WebDriverWait(driver, 20, 1)

# 向指定的 url 发送 get 请求
driver.get(url)
# 也可以利用 BeautifulSoup 对获取到的 html 内容进行解析
# html = driver.page_source
# soup = BeautifulSoup(html, 'html.parser')

# 查找元素(直接查找)
article_loc = driver.find_element(by=By.XPATH, value="//*[@id='tbody']/tr[1]/td[1]/a")
# 查找元素(等到元素都加载完后再查找)
article_loc = wait.until(
    EC.presence_of_element_located((By.XPATH, "//*[@id='tbody']/tr[1]/td[1]/a"))
)
# 获取文章的链接
article_link = article_loc.get_attribute(name='href')
1
2
3
4
5
6
7
8
9
# 模拟鼠标的移动和点击
ActionChains(driver).move_to_element(article_loc).perform()
article_loc.click()
# 模拟键盘的输入
ActionChains(driver).send_keys(Keys.SPACE).perform() #传入空格键

# 控制鼠标点击相应坐标
pyautogui.moveTo(1380, 650)
pyautogui.click() #控制鼠标点击
1
2
3
4
5
6
# 获取当前窗口
currentwindow = driver.current_window_handle
# 获取所有窗口,返回一个列表,里面放着一些窗口对象
all_window = driver.window_handles
# 切换窗口
driver.switch_to.window('某个窗口对象')

数据持久化

CSV / Excel

  • csv 文件的写入

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    import csv
    
    
    # 创建 CSV 文件,并写入表头信息
    # w+ 表示创建并写入
    with open('新建.csv', 'w+', newline='', encoding='utf-8-sig') as fp:
        writer = csv.writer(fp)
        writer.writerow(("标题", "时间", "URL", "正文内容", "来源"))
    
    
    # 将数据写入 csv 文件
    # a+ 表示追加写入
    with open('新建.csv', 'a+', newline='', encoding='utf-8-sig') as fp:
        writer = csv.writer(fp)
        writer.writerow((title, publish_time, article_link, article_text, source))
    

    newline 参数
    用于控制行尾的行为,保持 CSV 文件中的换行符一致性
    不同操作系统使用不同的行尾符号来表示换行
    在 Windows 中使用 \r\n,在 Unix/Linux 中使用 \n
    设置 newline='' 来告诉 Python 在写入文件时 不要自动插入额外的换行符

JSON

1
2
3
4
5
import json

json_str = json.dumps(dict_data, ensure_ascii=False, indent=2)
with open("data.json", "w", encoding="utf-8") as f:
    f.write(json_str)

反爬虫策略

策略 关键实现 参考
User-Agent 轮换 随机挑选 User-Agent 列表
代理 IP 池 使用住宅/付费代理,降低单 IP 风险
完整请求头 包含 RefererAccept-Language
动态渲染 Selenium/Playwright 执行 JS,获取完整页面
加密参数 逆向 JS 加密或使用 js2py 模拟
验证码 手工识别或接入第三方识别服务
请求频率控制 随机延时 1‑3 s,避免触发 IP 封禁
  • 示例:轮换 User-Agent 与代理
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import random, requests

USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/108.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/108.0.0.0 Safari/537.36",
    # 更多...
]

PROXIES = [
    {"http": "http://user:pass@proxy1:8080", "https": "https://user:pass@proxy1:8080"},
    {"http": "http://user:pass@proxy2:8080", "https": "https://user:pass@proxy2:8080"},
]

def fetch(url):
    hdr = {"User-Agent": random.choice(USER_AGENTS)}
    prx = random.choice(PROXIES)
    resp = requests.get(url, headers=hdr, proxies=prx, timeout=10)
    return resp.text
阶段 项目示例 目标技能
入门 爬取天气/新闻头条 基本请求、解析、存储
进阶 电商商品信息抓取(含登录) 代理、验证码、动态渲染
高级 社交媒体舆情分析(大规模) 分布式爬虫、反爬全链路

建议:从小项目开始,逐步加入代理、Selenium、加密处理等高级技巧,形成完整的爬虫工程能力。

法律和道德

了解版权法、隐私法等
在爬取数据时遵守道德规范,不滥用爬虫技术

  • 知识产权
    • 商标:TM 或者是 R 加一个圈(™)
    • 版权:C 加一个圈(©)
    • 专利
  • 不控制速度的话会造成的问题
    1、过度消耗别人的服务器资源,是非法的
    2、可能导致一个小型的网站下线,是不道德的

一般大型网站根目录会有 robots.txt 文件
用来禁止使用爬虫采集网页来收集网站信息的机器人
之所以不让爬取,是因为其网站本身提供了 API
通过 API 接口可以更容易控制数据内容,也可以通过对用户授权获利

robots.txt 文件没有标准的语法格式,并不是强制性约束