如何完成一个完整的网站信息爬取脚本

1、数据信息准备

首先当然是准备好要目标网站信息了

一、首先需要获取「登录相关信息」(关键!)

如果网站需要登录,脚本必须先模拟登录才能进行后续操作。请按以下步骤获取信息:

 打开登录页面:访问 
http://XXXX/XXXX/
,进入登录界面(如果未自动跳转,请找到登录入口)。

打开开发者工具:按 
F12
 打开浏览器开发者工具,切换到「Network(网络)」标签页,勾选「Preserve log(保留日志)」(避免登录过程中请求被清空)。

手动完成一次登录输入你的账号密码,点击登录按钮,观察「Network」面板中出现的新请求。

找到登录请求在「Network」面板的请求列表中,找到一个POST 类型的请求(通常 URL 包含 “login”“auth” 等关键词,比如 
http://XXX/api/login
),点击这个请求,查看右侧详情:

需要记录:



「Request Headers」中的「User-Agent」:复制下来(脚本需要模拟浏览器标识)。
「Form Data」或「Payload」:登录时提交的参数(例如 username=你的账号&password=你的密码&captcha=验证码,如果有验证码需要特别说明)。
「Request Method」:确认是 POST(大部分登录是 POST)。
「Request URL」:登录请求的接口地址(例如 http://xxx/login)。

二、获取「搜索查询相关信息」

登录后,手动完成一次搜索(例如输入 “AA”,选择 “描述”,点击查询),按以下步骤获取信息:

监控搜索请求保持「Network」面板开启,点击查询按钮后,找到触发的新请求(可能是 POST 或 GET,通常是 XHR 类型的异步请求,在「XHR/fetch」子标签页中更容易找到)。

记录搜索请求的关键信息点击这个搜索请求,查看右侧详情:

「Request URL」:搜索接口的地址(例如 
http://xxx/search
)。「Request Method」:POST 或 GET(决定脚本中参数的传递方式)。「Form Data」或「Query String Parameters」:搜索时提交的参数,需要重点记录:
关键字参数名:例如 
keyword=偏航
 中的 
keyword
。选项参数名:例如选择 “现象描述” 对应的参数,可能是 
type=description
 或 
category=1
(需要确认参数名和选项对应的取值,比如 “现象描述” 对应 1,“jira 链接” 对应 2 等)。
「Response」:查看返回的响应内容(是 JSON 格式还是 HTML 格式?如果是 JSON,结构是什么样的?这决定了后续如何提取数据)。

三、需要你确认的其他信息

登录后是否需要验证码?登录时需要输入验证码,可能需要手动输入或调用验证码识别接口搜索结果的结构
在「Response」中查看:搜索结果对应的数据字段(例如 
details: [{id: 1, title: "...", xx: "..."}, ...]
)。(如果是 HTML 格式,例如 
<div class="report">...</div>
)。”需要获得返回值”对应的数据字段(例如 
report: {bug: 10, task: 5}
)。

2、脚本配置参数

1. 登录相关配置:配置好对应的信息(下述举例)



LOGIN_URL # 登录接口
USERNAME # 你的用户名(固定)
PASSWORD # 你的加密密码(固定)
DEVICE  # 设备标识(固定)
SERVICE # 登录后跳转服务(固定)

2. 搜索相关配置:配置好对应的信息(下述举例)



SEARCH_URL # 搜索接口
SEARCH_PARAMS # 包括搜索关键词、返回条数、数据时间区间等

3. 保存路径配置:



SAVE_DIR = "./triangle_crawl_results"
if not os.path.exists(SAVE_DIR):
    os.makedirs(SAVE_DIR)  # 自动创建文件夹

3、功能函数

1、创建会话

函数功能:

创建一个持久化的HTTP会话对象设置必要的请求头信息返回配置好的会话对象

关键实现点:

使用
requests.Session()
创建会话对象,保持cookies和连接池设置了
User-Agent
模拟浏览器访问,避免被识别为爬虫设置了
Content-Type
为表单提交格式设置了
Referer
头,这是登录页面URL,有些网站会验证这个头



def create_session():
    """创建会话(保持登录状态)"""
    session = requests.Session()
    # 设置浏览器请求头,避免被识别为爬虫
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
        "Referer": "https://xxx/login?service=" + SERVICE
    })
    return session

小白理解:


Session()
就像一本笔记本,可以记住你和网站的对话
headers 
就像便利贴,告诉网站一些基本信息
User-Agent:假装是Chrome浏览器(很多网站不喜欢爬虫程序访问)Content-Type:告诉网站我会发送什么样的数据Referer:告诉网站我是从哪个页面过来的(有些网站会检查这个)
为什么需要这些?
保持登录状态:就像你登录后不用每次都输密码伪装成浏览器:避免被网站发现是程序在访问设置正确格式:让网站能正确理解我们发送的数据
使用例子:



# 先准备好"笔记本"
my_session = create_session()
 
# 然后用这个"笔记本"登录网站
my_session.post("登录网址", data={"用户名":"xxx", "密码":"xxx"})
 
# 再访问其他页面时,会自动保持登录状态
my_session.get("个人主页网址")

2、登录函数



def login(session):
    """登录函数:输入otp临时口令,完成登录并验证/不需要本步骤可以跳过"""
    # 获取实时otp(用户手动输入)
    otp = input("请输入30秒内有效的otp临时口令(如111222):").strip()
    if not otp.isdigit() or len(otp) != 6:
        print("错误:otp必须是6位数字!")
        return False
 
    # 构造登录请求参数;举例如下
    login_data = {
        "username": USERNAME,
        "password": PASSWORD,
        "add_trust_device": "on",
        "otp": otp,
        "device": DEVICE,
        "service": SERVICE
    }
 
    try:
        # 发送登录请求
        response = session.post(LOGIN_URL, data=login_data, timeout=15)
        response.raise_for_status()  # 若状态码非200,抛出异常
 
        # 验证登录是否成功(跳转至目标页面即为成功)
        test_response = session.get("http://xxx/triangle/", timeout=10)
        if "triangle" in test_response.url or test_response.status_code == 200:
            print("✅ 登录成功!")
            return True
        else:
            print("❌ 登录失败:未跳转到目标页面")
            return False
 
    except Exception as e:
        print(f"❌ 登录出错:{str(e)}")
        return False

3、爬取搜索结果函数

函数功能:

用于爬取搜索结果的函数通过POST请求发送搜索参数处理并验证返回的JSON数据打印搜索结果的统计信息返回完整数据或错误处理



def crawl_search_data(session):
    """爬取搜索结果:发送搜索请求,返回完整JSON数据"""
    try:
        print(f"
🔍 正在搜索关键词:{SEARCH_PARAMS['searchQuery']}")
        # 发送搜索POST请求(参数需转成JSON字符串)
        response = session.post(
            SEARCH_URL,
            data=json5.dumps(SEARCH_PARAMS),  # 适配特殊JSON格式
            headers={"Content-Type": "application/json"},  # 搜索接口需JSON格式
            timeout=20
        )
        response.raise_for_status()
 
        # 解析JSON响应
        data = response.json()
        # 验证数据完整性(包含feedback/reportData即为成功)
        required_keys = ["feedback","reportData"]
        if all(key in data for key in required_keys):
            print(f"✅ 搜索成功!获取到:")
            print(f"   - 相似结果:{len(data['feedback'])} 条")
            print(f"   - 统计报告:{len(data['reportData'])} 项")
            return data
        else:
            print(f"❌ 搜索数据不完整,缺少关键字段")
            return None
 
    except Exception as e:
        print(f"❌ 搜索出错:{str(e)}")
        return None

4、保存数据

函数功能:

将爬取的Jira数据保存到Excel文件创建包含2个工作表的Excel文件:
feedbackreportData
自动生成带时间戳的文件名避免覆盖返回生成的Excel文件路径



def save_to_excel(data, keyword):
    """将数据保存到Excel:分工作表(结果、统计报告)"""
    # 生成带时间戳的文件名(避免覆盖)
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    excel_path = os.path.join(SAVE_DIR, f"triangle_{keyword}_{timestamp}.xlsx")
 
    # 创建Excel工作簿
    wb = Workbook()
 
    # -------------------------- 1. 工作表1:用户反馈(feedback)--------------------------
    ws1 = wb.active
    ws1.title = "结果"
    # 表头(对应feedback的字段)
    feedback_headers = ["id", "content", "device", "input_date", "project_code",
                        "similarity", "submitter_role", "key", "status", "url"]
    ws1.append(feedback_headers)
    # 填充数据
    for item in data["feedback"]:
        ws1.append([
            item["id"],
            item["content"],
            item["device"],
            item["input_date"],
            item["project_code"],
            item["similarity"],
            item["submitter_role"],
            item["key"] or "",  # 空值处理
            item["status"] or "",
            item["url"]
        ])
 
   
    
    # -------------------------- 2. 工作表2:统计报告(reportData)--------------------------
    ws2 = wb.create_sheet(title="统计报告")
    # 统计报告分3类:priority(优先级)、status(状态)、resolution(解决结果)
    ws2.append(["统计类型", "分类", "阻断级(Blocker)", "严重级(Critical)", "主要级(Major)",
                "其他(Other)", "总计(Total)", "已关闭(Closed)", "处理中(InProgress)",
                "已解决(Resolved)", "已验证(Verified)", "待处理(Open)", "按设计(ByDesign)",
                "无法复现(CannotReproduce)", "重复(Duplicate)", "外部问题(External)",
                "已修复(Fixed)", "非问题(NotAnIssue)", "未解决(Unresolved)")
 
    for report in data["reportData"]:
        # 按统计类型填充对应字段(空值填0)
        row = [
            report["type"],  # 统计类型:priority/status/resolution
            report["category"],  # 分类:如“测试报告”
            report.get("blocker", 0),
            report.get("critical", 0),
            report.get("major", 0),
            report.get("other", 0),
            report.get("total", 0),
            report.get("closed", 0),
            report.get("inProgress", 0),
            report.get("resolved", 0),
            report.get("verified", 0),
            report.get("open", 0),
            report.get("byDesign", 0),
            report.get("cannotReproduce", 0),
            report.get("duplicate", 0),
            report.get("external", 0),
            report.get("fixed", 0),
            report.get("notAnIssue", 0),
            report.get("unresolved", 0),
        ]
        ws2.append(row)
 
    # 保存Excel文件
    wb.save(excel_path)
    print(f"
📊 Excel文件已保存:{excel_path}")
    return excel_path


def save_to_json(data, keyword):
    """将原始JSON数据保存到文件(便于后续处理)"""
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    json_path = os.path.join(SAVE_DIR, f"triangle_{keyword}_{timestamp}.json")
 
    with open(json_path, "w", encoding="utf-8") as f:
        json5.dump(data, f, ensure_ascii=False, indent=2)  # 格式化输出,支持中文
 
    print(f"📄 JSON文件已保存:{json_path}")
    return json_path

5、执行函数



if __name__ == "__main__":
 
    # 1. 创建会话
    session = create_session()
 
    # 2. 登录(重试3次机会)
    login_success = False
    for _ in range(3):
        if login(session):
            login_success = True
            break
        else:
            print(f"🔄 剩余登录重试次数:{2 - _}")
            time.sleep(2)  # 间隔2秒再重试
 
    if not login_success:
        print("
❌ 登录失败次数过多,程序退出")
        exit()
 
    # 3. 爬取搜索数据
    data = crawl_search_data(session)
    if not data:
        print("
❌ 未获取到有效数据,程序退出")
        exit()
 
    # 4. 保存数据(Excel + JSON)
    keyword = SEARCH_PARAMS["searchQuery"]
    save_to_excel(data, keyword)
    save_to_json(data, keyword)
 
    print("
" + "=" * 60)
    print("任务完成!文件已保存至:", SAVE_DIR)
    print("=" * 60)

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
Jiu咪露的头像 - 宋马
评论 抢沙发

请登录后发表评论

    暂无评论内容