雜表格和嵌套結(jié)構(gòu))
「AI Python 系列」第 03 欄 · Python 爬蟲實(shí)戰(zhàn)全欄 15 篇 · 零成本跟完 作者梅雅達(dá)編程筆記首發(fā)CSDN摘要有些網(wǎng)頁結(jié)構(gòu)復(fù)雜到XPath根本寫不出來——嵌套表格、混合排版、圖文混排。這時(shí)候與其死磕HTML結(jié)構(gòu)不如換個(gè)思路截圖讓視覺模型看圖說話。Day 13教你用GLM-4V-Flash視覺模型直接把頁面截圖扔給它讓它輸出你要的結(jié)構(gòu)化數(shù)據(jù)。對比文本模型和視覺模型各自的適用場景讓你知道什么時(shí)候該用哪個(gè)。前面講了用文本模型處理 HTML。但有些頁面給你 HTML 也沒用表格嵌套了好幾層td里套div再套table數(shù)據(jù)散落在不同位置靠排版讓人看懂HTML 結(jié)構(gòu)完全沒邏輯圖片里包含文字信息比如價(jià)格標(biāo)簽是張圖片Canvas渲染的圖表數(shù)據(jù)這時(shí)候XPath、正則、甚至文本大模型都幫不了你。該請視覺模型上場了。一、視覺模型能做什么簡單說你給它一張圖片它告訴你圖片里有什么。GLM-4V-Flash 是智譜的免費(fèi)視覺模型可以理解圖片內(nèi)容并回答問題。我們的用法用DrissionPage把頁面截圖把截圖發(fā)給 GLM-4V-Flash讓模型從圖片中提取你要的結(jié)構(gòu)化數(shù)據(jù)返回 JSON不用分析 HTML不用寫選擇器你看到什么AI 就能提取什么。二、基礎(chǔ)流程第一步頁面截圖用DrissionPage截圖fromDrissionPageimportChromiumPage pageChromiumPage()page.get(https://example-complex-table.com/)# 全屏截圖page.get_screenshot(pathpage_screenshot.png)# 或者只截某個(gè)區(qū)域注意page.ele 可能命中隱藏的布局表格# 建議遍歷找第一個(gè)有寬高的可見表格避免 NoRectErrorelementNoneforeleinpage.eles(css:table):try:w,hele.rect.sizeifwandhandw0andh0:elementelebreakexceptException:continueifelementisNone:page.get_screenshot(pathtable_only.png)# 兜底整頁截圖else:element.scroll.to_see()# 滾動(dòng)到表格位置確保完整渲染element.get_screenshot(pathtable_only.png)page.quit()踩坑提醒很多網(wǎng)站尤其是政府網(wǎng)站的第一個(gè)table是用來做頁面布局的隱藏表格display:none沒有寬高。直接用page.ele(css:table)再get_screenshot()會(huì)報(bào)NoRectError: 該元素沒有位置及大小。上面的遍歷寫法可以自動(dòng)跳過隱藏表格找到第一個(gè)真正可見的。第二步發(fā)給視覺模型importbase64fromopenaiimportOpenAI clientOpenAI(api_keyYOUR_API_KEY,base_urlhttps://open.bigmodel.cn/api/paas/v4/)# 讀取圖片并編碼withopen(table_only.png,rb)asf:img_base64base64.b64encode(f.read()).decode()# 調(diào)用視覺模型responseclient.chat.completions.create(modelglm-4v-flash,# GLM-4V-Flash 視覺模型messages[{role:user,content:[{type:text,text:請從這張圖片中的表格里提取所有數(shù)據(jù)返回 JSON 數(shù)組。每行一個(gè)對象字段名用表格的表頭。},{type:image_url,image_url:{url:fdata:image/png;base64,{img_base64}}}]}])print(response.choices[0].message.content)就這么簡單。截圖 → 發(fā)給模型 → 拿到結(jié)果。三、實(shí)戰(zhàn)從復(fù)雜公告頁提取表格數(shù)據(jù)場景假設(shè)你要從政府網(wǎng)站提取一份公告中的表格數(shù)據(jù)。這個(gè)表格合并了單元格、嵌套了子表格HTML 結(jié)構(gòu)極其復(fù)雜tableclassgovernment-noticetrtdcolspan32026年度重點(diǎn)項(xiàng)目公示/td/trtrtdrowspan2序號(hào)/tdtd項(xiàng)目名稱/tdtd預(yù)算萬元/td/trtrtdcolspan2詳細(xì)信息/td/tr!-- 后面還有幾十行嵌套結(jié)構(gòu) --/table用XPath提取寫到你懷疑人生。用視覺模型解決 Day 13 示例代碼視覺模型提取復(fù)雜表格 作者梅雅達(dá)編程筆記 fromDrissionPageimportChromiumPageimportbase64importjsonimporttimefromopenaiimportOpenAI clientOpenAI(api_keyYOUR_API_KEY,base_urlhttps://open.bigmodel.cn/api/paas/v4/)deffind_visible_table(page,timeout10):遍歷頁面所有 table返回第一個(gè)真正可見有寬高的元素。 政府網(wǎng)站常有隱藏的布局表格直接 page.ele 會(huì)報(bào) NoRectError。 page.wait.ele_displayed(css:table,timeouttimeout)foreleinpage.eles(css:table):try:w,hele.rect.sizeifwandhandw0andh0:returneleexceptException:continuereturnNonedefscreenshot_table(page,path):截取頁面中第一個(gè)可見表格找不到則整頁截圖兜底。tablefind_visible_table(page)iftableisNone:print(未找到可見表格改為整頁截圖)page.get_screenshot(pathpath)else:table.scroll.to_see()time.sleep(0.5)# 等滾動(dòng)后的渲染table.get_screenshot(pathpath)defextract_table_from_image(image_path,prompt):用視覺模型從圖片中提取結(jié)構(gòu)化數(shù)據(jù)withopen(image_path,rb)asf:img_base64base64.b64encode(f.read()).decode()responseclient.chat.completions.create(modelglm-4v-flash,messages[{role:user,content:[{type:text,text:prompt},{type:image_url,image_url:{url:fdata:image/png;base64,{img_base64}}}]}],temperature0.1)contentresponse.choices[0].message.content.strip()# 提取 JSONifjsonincontent:contentcontent.split(json)[1].split()[0]elifincontent:contentcontent.split()[1].split()[0]returnjson.loads(content)defmain():# 1. 打開頁面并截圖pageChromiumPage()page.get(http://www.ccgp.gov.cn/cggg/dfgg/zbgg/202607/t20260716_26951272.htm)# 截圖只截可見表格區(qū)域已修復(fù) NoRectErrorscreenshot_table(page,table_screenshot.png)page.quit()# 2. 用視覺模型提取prompt請從這張表格截圖中提取所有數(shù)據(jù)。 要求 1. 返回 JSON 數(shù)組每行一個(gè)對象 2. 字段名使用表格的表頭 3. 合并單元格的內(nèi)容填到對應(yīng)的每一行 4. 如果有子表格展開到同一層級 5. 只返回 JSON不要其他內(nèi)容 示例輸出格式 [ {序號(hào): 1, 項(xiàng)目名稱: 智慧城市項(xiàng)目, 預(yù)算_萬元: 5000, 負(fù)責(zé)人: 張三}, {序號(hào): 2, 項(xiàng)目名稱: 數(shù)據(jù)平臺(tái)項(xiàng)目, 預(yù)算_萬元: 3000, 負(fù)責(zé)人: 李四} ]print(正在用視覺模型分析表格...)dataextract_table_from_image(table_screenshot.png,prompt)print(f\n提取到{len(data)}條數(shù)據(jù))print(-*60)foritemindata:print(json.dumps(item,ensure_asciiFalse))# 3. 保存importpandasaspd dfpd.DataFrame(data)df.to_csv(extracted_table.csv,indexFalse,encodingutf-8-sig)print(f\n已保存到 extracted_table.csv)if__name____main__:main()運(yùn)行結(jié)果示例正在用視覺模型分析表格... 提取到 1 條數(shù)據(jù) ------------------------------------------------------------ {供應(yīng)商名稱: 甘肅禾木物業(yè)有限責(zé)任公司, 供應(yīng)商地址: 甘肅省張掖市山丹縣南大街16號(hào), 中標(biāo)金額: 2627700.00, 評審得分: 82.19} 已保存到 extracted_table.csv四、視覺模型 vs 文本模型兩種方法各有優(yōu)劣不是替代關(guān)系維度文本模型處理 HTML視覺模型處理截圖速度快文本傳輸慢圖片傳輸 理解成本低文本 token 少高圖片 token 多準(zhǔn)確率高數(shù)據(jù)結(jié)構(gòu)清晰時(shí)中高偶爾識(shí)別錯(cuò)誤適用場景結(jié)構(gòu)化的 HTML復(fù)雜排版、圖片數(shù)據(jù)、Canvas抗改版中改 HTML 結(jié)構(gòu)可能失效高只要視覺上沒變就不影響什么時(shí)候用視覺模型HTML 結(jié)構(gòu)極度復(fù)雜文本模型搞不定數(shù)據(jù)在圖片里價(jià)格標(biāo)簽、二維碼、圖表Canvas渲染的內(nèi)容ECharts圖表、地圖需要 OCR 的場景掃描件、PDF 截圖頁面頻繁改版你不想每次都改解析代碼什么時(shí)候用文本模型HTML 結(jié)構(gòu)規(guī)整選擇器好寫數(shù)據(jù)量大需要考慮成本和速度批量處理幾千條數(shù)據(jù)最佳實(shí)踐先用文本不行再視覺defsmart_extract(url,prompt_template):智能提取先嘗試文本模型失敗再上視覺模型# 1. 先嘗試直接獲取 HTML 文本模型try:responserequests.get(url,headersheaders)htmlresponse.text# 用文本模型提取dataextract_with_text_model(html,prompt_template)ifdataandlen(data)0:print(文本模型提取成功)returndataexcept:pass# 2. 文本模型搞不定用視覺模型print(文本模型提取失敗切換到視覺模型...)pageChromiumPage()page.get(url)page.get_screenshot(pathtemp_screenshot.png)page.quit()dataextract_with_vision_model(temp_screenshot.png,prompt_template)print(視覺模型提取完成)returndata五、更多應(yīng)用場景1. 提取圖表數(shù)據(jù)prompt這張圖片包含一個(gè)柱狀圖/折線圖。 請?zhí)崛D表中的所有數(shù)據(jù)點(diǎn)返回 JSON 數(shù)組。 格式[{label: 類別名, value: 數(shù)值}] 如果有多個(gè)系列每個(gè)系列分別提取。2. 提取圖片中的價(jià)格prompt這張圖片是商品列表頁的截圖。 請?zhí)崛∶總€(gè)商品的名稱和價(jià)格返回 JSON 數(shù)組。 格式[{name: 商品名, price: 數(shù)字, unit: 單位}] 注意識(shí)別圖片中的價(jià)格標(biāo)簽。3. 提取地圖標(biāo)注prompt這張圖片是一張地圖上面標(biāo)注了一些位置點(diǎn)。 請?zhí)崛∷袠?biāo)注點(diǎn)的信息返回 JSON 數(shù)組。 格式[{name: 地點(diǎn)名, description: 描述如果有}]4. 提取 PDF 掃描件# 先把 PDF 轉(zhuǎn)成圖片再用視覺模型提取frompdf2imageimportconvert_from_path imagesconvert_from_path(scanned_document.pdf)fori,imginenumerate(images):img.save(fpage_{i}.png)dataextract_with_vision_model(fpage_{i}.png,prompt)六、提高視覺模型準(zhǔn)確率的技巧1. 截圖要清晰# 放大頁面再截圖提高清晰度page.run_js(document.body.style.zoom 1.5)time.sleep(1)page.get_screenshot(pathzoomed_screenshot.png)2. 只截需要的部分# 不要全屏截圖只截目標(biāo)區(qū)域# 復(fù)用上面的 screenshot_table() 函數(shù)自動(dòng)跳過隱藏表格screenshot_table(page,target.png)3. Prompt 要具體# 模糊的 prompt不好prompt提取表格數(shù)據(jù)# 具體的 prompt好prompt提取圖片中的表格數(shù)據(jù) - 第一列是序號(hào)整數(shù) - 第二列是項(xiàng)目名稱字符串 - 第三列是金額數(shù)字單位萬元 - 第四列是狀態(tài)字符串 返回 JSON 數(shù)組只返回 JSON。4. 大圖分段處理defsplit_and_extract(image_path,rows_per_chunk20):大表格分段截圖提取fromPILimportImage imgImage.open(image_path)width,heightimg.size# 估算每段高度根據(jù)行高row_height40# 每行大約 40 像素chunk_heightrows_per_chunk*row_height100# 加上表頭all_data[]forstart_yinrange(0,height,chunk_height-100):# 重疊100像素保證不丟行# 裁剪end_ymin(start_ychunk_height,height)chunkimg.crop((0,start_y,width,end_y))chunk_pathfchunk_{start_y}.pngchunk.save(chunk_path)# 提取dataextract_with_vision_model(chunk_path,prompt)all_data.extend(data)# 去重重疊部分可能有重復(fù)數(shù)據(jù)# ...returnall_data 本篇成本透明欄項(xiàng)目數(shù)值A(chǔ)PI 調(diào)用次數(shù)~5-20 次取決于頁面數(shù)消耗 Token約 5-20 萬 tokens圖片 token 較多成本¥0GLM-4V-Flash 免費(fèi)額度內(nèi)視覺模型的圖片 token 消耗比文本高但免費(fèi)額度一般夠用。練手改造題改造 1基礎(chǔ)打開一個(gè)包含復(fù)雜表格的網(wǎng)站比如統(tǒng)計(jì)局?jǐn)?shù)據(jù)頁用DrissionPage截圖然后用視覺模型提取表格數(shù)據(jù)。對比你手動(dòng)看頁面和 AI 提取的結(jié)果。改造 2進(jìn)階找一個(gè)包含ECharts圖表的網(wǎng)頁截圖后用視覺模型提取圖表的數(shù)據(jù)點(diǎn)。嘗試還原出原始數(shù)據(jù)。下期預(yù)告Day 14 · 實(shí)戰(zhàn)數(shù)據(jù)采集全流程 Pipeline前面學(xué)的東西要串起來了。Day 14 從零搭建一個(gè)完整的數(shù)據(jù)采集系統(tǒng)——目標(biāo)電商商品價(jià)格監(jiān)控。包含分析頁面、編寫爬蟲、數(shù)據(jù)存儲(chǔ)、AI 清洗、輸出報(bào)告一條龍走完。 資源與工具智譜 GLM-4V-Flash視覺模型https://open.bigmodel.cn/DrissionPage 文檔https://g1879823.gitlab.io/DrissionPage/本專欄配套代碼CSDN 下載區(qū)每篇更新梅雅達(dá)編程筆記專注 Python AI 實(shí)戰(zhàn)教程提供數(shù)據(jù)采集與自動(dòng)化定制服務(wù)往期回顧Day 01 · 爬蟲能干啥不能干啥Day 02 · 環(huán)境搭建與第一個(gè)爬蟲Day 03 · 列表頁抓取批量拿數(shù)據(jù)Day 04 · 詳情頁 翻頁從一條到一百條Day 05 · Ajax 請求攔截抓看不到的數(shù)據(jù)Day 06 · 瀏覽器自動(dòng)化DrissionPage 實(shí)戰(zhàn)Day 07 · Cookie 與 Session處理登錄狀態(tài)Day 08 · 反爬對策Headers 限速 代理Day 09 · 存成文件CSV / Excel / JSONDay 10 · 存進(jìn)數(shù)據(jù)庫SQLite 從零上手Day 11 · 用 AI 替代正則智能提取結(jié)構(gòu)化數(shù)據(jù)Day 12 · AI 數(shù)據(jù)清洗臟數(shù)據(jù)一鍵變干凈專欄「AI Python 系列」 第 03 欄 ·AIPython 爬蟲實(shí)戰(zhàn)「AI Python 系列」第 01 欄 ·AI辦公自動(dòng)化「AI Python 系列」第 02 欄 ·AI數(shù)據(jù)可視化「AI Python 系列」第 05 欄 · AI Agent實(shí)戰(zhàn)資源領(lǐng)取關(guān)注作者獲取本欄完整代碼和數(shù)據(jù)集原創(chuàng)聲明本文為梅雅達(dá)編程筆記原創(chuàng)作品未經(jīng)允許不得轉(zhuǎn)載。