You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

网站重发后PDF内嵌QR码无法识别,求Python代码修复方案

问题描述

我们完成了网站重发,现有数百份带印刷QR码的多语言PDF文件。重发后发现部分QR码指向的URL不正确,为了减少人工工作量,我写了Python代码,打算批量下载PDF、扫描识别QR码、提取URL并检测状态码,最终生成包含文档与链接的表格。但代码无法识别QR码,求帮忙修复。

附上当前代码:

import os
import requests
import fitz  # PyMuPDF
import cv2
from pyzbar.pyzbar import decode
import numpy as np
import csv
import pdfplumber

# 下载PDF的函数
def download_pdf(url, save_path):
    if os.path.exists(save_path):
        print(f"{save_path} already exists, skipping download.")
        return True
    response = requests.get(url)
    if response.status_code == 200:
        with open(save_path, 'wb') as f:
            f.write(response.content)
        print(f"Downloaded {url}")
        return True
    else:
        print(f"Failed to download {url}, status code: {response.status_code}")
        return False

# 将PDF页面转为图像的函数(使用PyMuPDF)
def pdf_to_images(pdf_path):
    doc = fitz.open(pdf_path)
    images = []
    for page in doc:
        pix = page.get_pixmap()
        if pix.alpha:
            img = np.frombuffer(pix.samples, dtype=np.uint8).reshape(pix.height, pix.width, 4)
        else:
            img = np.frombuffer(pix.samples, dtype=np.uint8).reshape(pix.height, pix.width, 3)
        images.append(img)
    return images

# 从图像中提取QR码的函数
def extract_qr_codes(image):
    qr_codes = decode(image)
    return [qr.data.decode('utf-8') for qr in qr_codes]

# 检查URL状态码的函数
def check_url(url):
    try:
        response = requests.head(url, allow_redirects=True)
        return response.status_code
    except requests.RequestException as e:
        print(f"Error checking URL {url}: {e}")
        return 'Error'

# 使用pdfplumber提取图像并解码QR码的备用方法
def extract_images_and_decode_qr(pdf_path):
    with pdfplumber.open(pdf_path) as pdf:
        for page in pdf.pages:
            im_list = page.images
            for im in im_list:
                bbox = (im['x0'], im['top'], im['x1'], im['bottom'])
                cropped_image = page.crop(bbox).to_image(resolution=300)
                image = np.array(cropped_image.original)
                image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
                qr_codes = decode(image)
                for qr in qr_codes:
                    print("Gefundener QR-Code:", qr.data.decode())

# 处理PDF的主函数
def process_pdfs(url_list):
    results = []
    for url in url_list:
        pdf_filename = os.path.basename(url)
        pdf_path = os.path.join('downloads', pdf_filename)
        
        if not os.path.exists('downloads'):
            os.makedirs('downloads')
        
        if download_pdf(url, pdf_path):
            print(f"Processing {pdf_path}...")
            images = pdf_to_images(pdf_path)
            for img in images:
                qr_urls = extract_qr_codes(img)
                for qr_url in qr_urls:
                    status_code = check_url(qr_url)
                    results.append((pdf_filename, qr_url, status_code))

            # 当未找到QR码时,尝试pdfplumber方法
            if not any(result[1] for result in results if result[0] == pdf_filename):
                extract_images_and_decode_qr(pdf_path)

    if results:
        with open('results.csv', 'w', newline='') as file:
            writer = csv.writer(file)
            writer.writerow(['PDF Name', 'QR Code', 'Target URL', 'Status Code'])
            for result in results:
                writer.writerow(result)
    else:
        print("No results to write to CSV.")

# 测试调用
if __name__ == "__main__":
    url_list = [
        "https:.....pdf"
    ]
    
    process_pdfs(url_list)
修复方案

以下是针对QR码无法识别问题的具体修复步骤:

1. 优化图像预处理逻辑

pyzbar对图像格式和清晰度敏感,修改extract_qr_codes函数,增加格式转换和对比度优化:

def extract_qr_codes(image):
    # 处理多通道图像,转成灰度图
    if len(image.shape) == 3:
        if image.shape[2] == 4:
            # RGBA转RGB再转灰度
            image = cv2.cvtColor(image, cv2.COLOR_RGBA2RGB)
        image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    # 增强图像对比度,提升印刷QR码的识别率
    image = cv2.equalizeHist(image)
    qr_codes = decode(image)
    return [qr.data.decode('utf-8') for qr in qr_codes]

2. 提高PDF转图像的分辨率

默认分辨率下生成的图像可能模糊,修改pdf_to_images函数,提高dpi:

def pdf_to_images(pdf_path):
    doc = fitz.open(pdf_path)
    images = []
    for page in doc:
        # 设置dpi为300,匹配印刷品的清晰度
        pix = page.get_pixmap(dpi=300)
        if pix.alpha:
            img = np.frombuffer(pix.samples, dtype=np.uint8).reshape(pix.height, pix.width, 4)
        else:
            img = np.frombuffer(pix.samples, dtype=np.uint8).reshape(pix.height, pix.width, 3)
        images.append(img)
    return images

3. 修复pdfplumber分支的结果收集逻辑

原代码中pdfplumber识别到QR码后仅打印,未写入CSV。修改extract_images_and_decode_qr函数让它返回结果,并在主函数中收集:

def extract_images_and_decode_qr(pdf_path):
    qr_results = []
    with pdfplumber.open(pdf_path) as pdf:
        for page in pdf.pages:
            im_list = page.images
            for im in im_list:
                bbox = (im['x0'], im['top'], im['x1'], im['bottom'])
                cropped_image = page.crop(bbox).to_image(resolution=300)
                image = np.array(cropped_image.original)
                image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
                # 同样增加对比度优化
                image = cv2.equalizeHist(image)
                qr_codes = decode(image)
                for qr in qr_codes:
                    qr_url = qr.data.decode('utf-8')
                    print("Gefundener QR-Code:", qr_url)
                    qr_results.append(qr_url)
    return qr_results

同时修改主函数中的调用部分:

# 替换原pdfplumber调用代码
if not any(result[1] for result in results if result[0] == pdf_filename):
    print(f"Using pdfplumber to scan {pdf_path}...")
    qr_urls = extract_images_and_decode_qr(pdf_path)
    for qr_url in qr_urls:
        status_code = check_url(qr_url)
        results.append((pdf_filename, qr_url, status_code))

4. 修正CSV表头与数据的匹配问题

原表头有4列,但数据仅3列,修改表头为对应格式:

writer.writerow(['PDF Name', 'QR Code URL', 'Status Code'])

内容的提问来源于stack exchange,提问作者PeterPan1888

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 10:37:05