项目中需要爬去多个网页的数据,一开始用xpath定位页面上的元素,解析数据,但是有个很大的问题,原始页面经常更细,我们也需要经常更新xpath,挺麻烦的。后来试着用大模型解析html,输出一个json,然后在提取我们想要的数据,效果还不错。
请求参数:
bash
{
"messages": [
{
"role": "user",
"content": "请解析一下html代码,找出代码中的table,解析出table的表头和自身数据。数据输出格式是一个json, 包含2个值, header存放表头信息,data存放表单数据。\n代码:\n<div class='table-container' id='tableContainer' style='display: block;'>\n <div class='table-scroll'>\n <table id='leaderboardTable'>\n <thead>\n <tr>\n <th class='rank-col'>Rank</th>\n <th class='model-col'>Model</th>\n <th class='score-col'>Pass@1</th>\n <th class='score-col'>Easy</th>\n <th class='score-col'>Medium</th>\n <th class='score-col'>Hard</th>\n </tr>\n </thead>\n <tbody id='tableBody' class=''><tr class='' data-model='O4-Mini (High)' style=''>\n <td class='rank-col'>\n <span class='rank-badge rank-1'>1</span>\n </td>\n <td class='model-col'>\n <a href='https://platform.openai.com/docs/api-reference/chat/create#chat-create-reasoning_effort' target='_blank'>O4-Mini (High)</a>\n </td>\n <td class='score-col'>80.2</td>\n <td class='score-col'>99.1</td>\n <td class='score-col'>89.4</td>\n <td class='score-col'>63.5</td>\n </tr><tr class='' data-model='O3 (High)' style=''>\n <td class='rank-col'>\n <span class='rank-badge rank-2'>2</span>\n </td>\n <td class='model-col'>\n <a href='https://platform.openai.com/docs/api-reference/chat/create#chat-create-reasoning_effort' target='_blank'>O3 (High)</a>\n </td>\n <td class='score-col'>75.8</td>\n <td class='score-col'>99.1</td>\n <td class='score-col'>84.4</td>\n <td class='score-col'>57.1</td>\n </tr><tr class='' data-model='O4-Mini (Medium)' style=''>\n <td class='rank-col'>\n <span class='rank-badge rank-3'>3</span>\n </td>\n <td class='model-col'>\n <a href='https://platform.openai.com/docs/api-reference/chat/create#chat-create-reasoning_effort' target='_blank'>O4-Mini (Medium)</a>\n </td>\n <td class='score-col'>74.2</td>\n <td class='score-col'>98.2</td>\n <td class='score-col'>86.5</td>\n <td class='score-col'>52.7</td>\n </tr><tr class='' data-model='Gemini-2.5-Pro-06-05' style=''>\n <td class='rank-col'>\n <span class='rank-badge rank-other'>4</span>\n </td>\n <td class='model-col'>\n <a href='https://blog.google/technology/google-deepmind/gemini-model-thinking-updates-march-2025/#advanced-coding' target='_blank'>Gemini-2.5-Pro-06-05</a>\n </td>\n <td class='score-col'>73.6</td>\n <td class='score-col'>99.1</td>\n <td class='score-col'>87.2</td>\n <td class='score-col'>50.2</td>\n </tr></tbody>\n </table>\n </div>\n</div>\n"
}
],
"model": "qwq-32b",
"stream": false,
"max_tokens": 4096,
"n": 1,
"stop": [
"<eod>",
"<|im_end|>",
"<|endoftext|>",
"<|im_start|>"
],
"temperature": 0.9,
"top_p": 0.6
}
返回值:
bash
{
"id": "chata4621438-7662-11f0-ab3f-fa163e83aa86",
"object": "chat.completion",
"created": 1754882741,
"model": "qwq-32b",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "<think>\n好的,我现在需要解析用户提供的HTML代码,提取表格的表头和数据,并以指定的JSON格式输出。首先,我应该仔细看一下用户提供的HTML结构,确保我理解其中的各个部分。\n\n首先,用户给的HTML中有一个包含表格的div,表格的id是leaderboardTable。表格的结构分为thead和tbody。表头在thead里,里面有一个tr包含多个th标签,每个th对应一个列的标题。数据行在tbody里,每个tr代表一行数据,里面的td对应各个列的数据。\n\n我的任务是提取表头的信息和每一行的数据,然后将它们整理成一个JSON对象,包含header和data两个键。其中header是一个数组,包含所有表头的文本;data是一个数组,每个元素是一个对象,属性名对应表头,属性值对应该行对应列的文本。\n\n首先,我需要确认表头部分。在thead的tr里,有六个th标签,分别是Rank、Model、Pass@1、Easy、Medium、Hard。所以header数组应该是[\"Rank\", \"Model\", \"Pass@1\", \"Easy\", \"Medium\", \"Hard\"]。\n\n接下来是数据部分。tbody里的每个tr对应一行数据。每个tr有六个td,分别对应表头的六个列。需要注意的是,每个td的类名可能和表头的类名对应,但用户可能只需要文本内容。例如,第一个td是rank-col,里面有一个span显示排名,比如1,所以直接取文本即可。第二个td是model-col,里面有一个a标签,文本是模型名称,比如O4-Mini (High),所以需要提取a标签的文本。后面的几个td都是直接包含分数的文本,如80.2等。\n\n需要注意的是,每个tr还有一个data-model属性,但用户可能不需要这个属性值,因为题目只要求提取表格中的数据,所以可以忽略这个属性。此外,每个td的结构可能不同,比如rank-col里的span,但只需要提取文本内容。\n\n现在,我需要遍历tbody中的每个tr,然后对于每个tr中的td,按顺序提取文本内容。例如,第一个tr的六个td的文本分别是1、O4-Mini (High)、80.2、99.1、89.4、63.5。这样,对应的数据对象应该是:\n{\n \"Rank\": \"1\",\n \"Model\": \"O4-Mini (High)\",\n \"Pass@1\": \"80.2\",\n \"Easy\": \"99.1\",\n \"Medium\": \"89.4\",\n \"Hard\": \"63.5\"\n}\n\n同样处理其他tr,得到所有数据行。需要注意的是,第二个tr的rank是2,第三个是3,第四个是4,对应的文本都要正确提取。\n\n现在,我需要确保没有遗漏任何数据行,并且每个td的顺序与表头对应。比如,检查每个tr的td数量是否与表头数量一致,都是6个。在提供的HTML中,每个tr确实有六个td,所以没问题。\n\n另外,注意模型名称的a标签的文本,比如第一个tr的第二个td中的a标签的文本是O4-Mini (High),需要正确提取。其他td的文本直接取即可,不需要处理子元素。\n\n最后,将所有这些整理成JSON格式。确保header数组正确,data数组中的每个对象的键名与header一致,并且顺序正确。例如,header的第一个元素是Rank,对应每个数据对象的第一个键。\n\n现在,我需要把这些步骤具体执行一遍,确保没有错误。例如,检查每个数据行的每个td的文本是否正确,特别是rank的span里的文本,以及模型名称的a标签的文本是否正确提取。\n\n总结步骤:\n1. 提取thead中的th文本作为header数组。\n2. 遍历tbody中的每个tr,提取每个td的文本内容。\n3. 将每个tr的td文本按顺序对应到header的键,生成一个对象。\n4. 将所有对象收集到data数组中。\n5. 构建最终的JSON对象,包含header和data。\n\n现在开始具体处理:\n\n表头部分:\nthead里的tr有六个th,顺序是:\n- Rank\n- Model\n- Pass@1\n- Easy\n- Medium\n- Hard\n所以header数组是正确的。\n\n数据部分:\n第一个tr:\n- Rank的td里的span文本是1 → \"1\"\n- Model的td里的a文本是O4-Mini (High) → \"O4-Mini (High)\"\n- Pass@1的td文本是80.2 → \"80.2\"\n- Easy是99.1 → \"99.1\"\n- Medium是89.4 → \"89.4\"\n- Hard是63.5 → \"63.5\"\n\n第二个tr:\n- Rank是2 → \"2\"\n- Model是O3 (High) → \"O3 (High)\"\n- Pass@1是75.8 → \"75.8\"\n- Easy是99.1 → \"99.1\"\n- Medium是84.4 → \"84.4\"\n- Hard是57.1 → \"57.1\"\n\n第三个tr:\n- Rank是3 → \"3\"\n- Model是O4-Mini (Medium) → \"O4-Mini (Medium)\"\n- Pass@1是74.2 → \"74.2\"\n- Easy是98.2 → \"98.2\"\n- Medium是86.5 → \"86.5\"\n- Hard是52.7 → \"52.7\"\n\n第四个tr:\n- Rank是4 → \"4\"(注意这里的span类是rank-other,但文本是4)\n- Model是Gemini-2.5-Pro-06-05 → \"Gemini-2.5-Pro-06-05\"\n- Pass@1是73.6 → \"73.6\"\n- Easy是99.1 → \"99.1\"\n- Medium是87.2 → \"87.2\"\n- Hard是50.2 → \"50.2\"\n\n确认所有数据正确无误后,将这些整理成JSON结构。注意JSON的键名要与header中的顺序一致,每个数据对象的键必须对应header的每个元素。\n\n最终的JSON应该像这样:\n{\n \"header\": [\"Rank\", \"Model\", \"Pass@1\", \"Easy\", \"Medium\", \"Hard\"],\n \"data\": [\n {\n \"Rank\": \"1\",\n \"Model\": \"O4-Mini (High)\",\n \"Pass@1\": \"80.2\",\n \"Easy\": \"99.1\",\n \"Medium\": \"89.4\",\n \"Hard\": \"63.5\"\n },\n ...其他三个对象...\n ]\n}\n\n检查每个数据对象的顺序是否与header一致,确保没有错位。例如,第二个数据对象的Pass@1是75.8,对应第二个tr的第三个td的文本。\n\n这样应该完成了用户的要求。最后再检查一遍JSON格式是否正确,比如逗号、引号等,确保没有语法错误。\n</think>\n\n```json\n{\n \"header\": [\"Rank\", \"Model\", \"Pass@1\", \"Easy\", \"Medium\", \"Hard\"],\n \"data\": [\n {\n \"Rank\": \"1\",\n \"Model\": \"O4-Mini (High)\",\n \"Pass@1\": \"80.2\",\n \"Easy\": \"99.1\",\n \"Medium\": \"89.4\",\n \"Hard\": \"63.5\"\n },\n {\n \"Rank\": \"2\",\n \"Model\": \"O3 (High)\",\n \"Pass@1\": \"75.8\",\n \"Easy\": \"99.1\",\n \"Medium\": \"84.4\",\n \"Hard\": \"57.1\"\n },\n {\n \"Rank\": \"3\",\n \"Model\": \"O4-Mini (Medium)\",\n \"Pass@1\": \"74.2\",\n \"Easy\": \"98.2\",\n \"Medium\": \"86.5\",\n \"Hard\": \"52.7\"\n },\n {\n \"Rank\": \"4\",\n \"Model\": \"Gemini-2.5-Pro-06-05\",\n \"Pass@1\": \"73.6\",\n \"Easy\": \"99.1\",\n \"Medium\": \"87.2\",\n \"Hard\": \"50.2\"\n }\n ]\n}\n```"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 852,
"completion_tokens": 1821,
"total_tokens": 2673
}
}