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

Python正则返回元组列表而非预期列表,爬取JS数组版本信息遇问题

嘿,我来帮你搞定这个问题!你提到用Python的re模块提取JS数组里的版本信息时,得到了元组列表但想要普通列表,结合你爬100多个网页的场景,咱们一步步来解决:

一、为啥会返回元组列表?

通常是因为你的正则表达式里用了多个捕获分组(就是那些括号),或者不小心加了不必要的括号。比如如果你写了类似这样的正则:

pattern = r"Appname\[(\d+)\]='(.*?)'; Appversion\[(\d+)\]='(.*?)'"
matches = re.findall(pattern, js_content)

re.findall会把每个分组的结果打包成元组,最后返回一堆元组组成的列表。如果只想要版本字符串的普通列表,或者把名字和版本整理成更实用的格式,咱们可以从两个方向调整。

二、解决方案:两种思路任选

1. 调整正则,直接得到普通列表(推荐)

如果你只需要Appversion的值,就把正则写成只捕获版本部分,去掉多余的括号:

import re
from bs4 import BeautifulSoup

# 假设你已经用BeautifulSoup拿到了页面内容
soup = BeautifulSoup(page_content, "html.parser")
script_tag = soup.find("script", language="Javascript")
js_content = script_tag.string

# 只匹配Appversion的内容,正则里只有一个捕获分组
version_pattern = r"Appversion\[\d+\]='(.*?)'"
versions = re.findall(version_pattern, js_content)
# 现在versions就是普通字符串列表啦,比如['6.02 TEST prod', '6.02 TEST ', '06.0001.00']

如果同时需要Appname和Appversion,想把元组转成更友好的格式(比如字典列表),可以这么写:

# 匹配名字和版本,两个有效捕获分组
name_version_pattern = r"Appname\[\d+\]='(.*?)';\s*Appversion\[\d+\]='(.*?)'"
matches = re.findall(name_version_pattern, js_content)
# 转成字典列表,方便后续处理
app_list = [{"应用名称": name, "版本号": version} for name, version in matches]

2. 直接处理已有的元组列表

如果不想改正则,就对已经得到的元组列表做转换:

# 假设你已经有了tuple_list = [('foobar', '6.02 TEST prod'), ('barfoo', '06.0001.00'), ...]
# 只提取版本号,得到普通列表
versions = [item[1] for item in tuple_list]
# 或者把所有元素扁平化,变成一个普通列表
flat_list = [content for tuple_item in tuple_list for content in tuple_item]
三、适配你爬取场景的完整脚本示例

结合遍历IP、爬取页面、提取版本、写入文件的流程,给你一个完整的参考片段:

import re
import requests
from bs4 import BeautifulSoup
import time

# 你的IP列表,替换成实际的
ip_list = ["192.168.1.1", "192.168.1.2", "192.168.1.3"]
output_file = "app_versions_record.txt"

with open(output_file, "w", encoding="utf-8") as f:
    for ip in ip_list:
        try:
            url = f"http://{ip}"
            # 加超时和小延迟,避免给服务器太大压力
            response = requests.get(url, timeout=10)
            response.raise_for_status()
            time.sleep(0.5)
            
            soup = BeautifulSoup(response.text, "html.parser")
            script_tag = soup.find("script", language="Javascript")
            if not script_tag:
                f.write(f"{ip}: 未找到目标JS脚本标签\n")
                continue
                
            js_content = script_tag.string
            # 兼容可能的单双引号和转义字符
            pattern = r"Appname\[(\d+)\]=(['\"])(.*?)\2;\s*Appversion\[(\d+)\]=(['\"])(.*?)\5"
            matches = re.findall(pattern, js_content)
            
            f.write(f"=== 服务器 {ip} 的应用版本信息 ===\n")
            # 提取名字和版本,跳过索引和引号分组
            for _, _, name, _, _, version in matches:
                f.write(f"应用名称: {name}, 版本号: {version}\n")
            f.write("\n")
            
        except Exception as e:
            f.write(f"{ip}: 请求失败 - {str(e)}\n")
            continue
四、几个实用小提示
  • 注意JS里的字符串可能用双引号,或者有转义的单引号(比如I\'m app),上面的正则用了(['\"])来兼容单双引号,\2和\5用来匹配对应的闭合引号,避免匹配出错。
  • 如果遇到压缩后的JS代码(没有换行),正则依然有效,因为\s*可以匹配任意空白字符(空格、换行、制表符都算)。
  • 爬100多个IP时,记得加个小延迟(比如time.sleep(0.5)),不然容易被目标服务器拦截或者造成服务压力。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:38:25