解析AJAX表格时无法提取bs4.element.Tag类型数据文本的问题
问题描述
- 解析AJAX表格数据时,得到的数据类型为
bs4.element.Tag,尝试用replace、strip等字符串处理函数无效,即使指定text属性也无法正确提取标记内文本。 - 包含评论数的元素类名为
tcl2,无法用re.sub删除类名中的“2”,因为评论数本身可能为2,会误删有效数据。
用户代码:
import requests from bs4 import BeautifulSoup from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry import json import re import time catalog = {} def parse (): header = { 'user-agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.167 YaBrowser/22.7.5.940 Yowser/2.5 Safari/537.36" } session = requests.Session() retry = Retry(connect=1, backoff_factor=0.5) adapter = HTTPAdapter(max_retries=retry) inb = 1 comp = 'all' while inb <= 1: url_not_based = (f"http://foodmarkets.ru/firms/filter_result/7/{comp}/0/posted/page{inb}/") session.mount(f'http://foodmarkets.ru/firms/filter_result/7/{comp}/0/posted/page{inb}/' ,adapter) r = session.get (url_not_based,verify=True,headers=header,timeout=5) soup = BeautifulSoup (r.text, "lxml") rounded_block = soup.find_all('tr') for round in rounded_block: round_сompany = round.find('td',class_='tcl'>'href') clear_comp1 = re.sub(r'[a-zA-Z<>/\t\n=''0-9.:"""']','',str(round_сompany)) clear_comp2 = re.sub(r'[\xa0]',' ',clear_comp1) round_сity = round.find('td',class_="tc2 nowrap") clear_city1 = re.sub(r'[a-zA-Z<>/\t\n=''0-9.:"""']','',str(round_сity)) clear_city2 = re.sub(r'[\xa0]',' ',clear_city1) round_сommment = round.find('td',class_="tc2 cntr") clear_comm1 = re.sub(r'[a-zA-Z<>""''/\t\n=.:]','',str( round_сommment)) if round_сompany in catalog: continue else: catalog [round_сompany] = { "Company": clear_comp2, "City":clear_city2, "Comment": clear_comm1, } inb = inb+1 time.sleep(0.5) # print (catalog) #with open ("catalog.json","w",encoding='utf-8') as file: # json.dump(catalog, file, indent=4, ensure_ascii=False) if __name__ == "__main__": parse()
解决方案
1. 正确提取bs4.element.Tag内的文本
bs4.element.Tag是BeautifulSoup的元素对象,不能直接用字符串处理函数,需用.text或.get_text()方法提取文本内容,无需通过正则暴力删除标签。同时注意代码中的语法错误:round_сompany = round.find('td',class_='tcl'>'href')是错误写法,应先定位目标td,再找到其中的<a>标签提取文本。
2. 评论数提取无需处理类名
元素类名tcl2是标记元素的属性,和元素内的评论数文本无关,直接提取该元素的文本即可,不需要对类名进行任何操作。
修正后的代码
import requests from bs4 import BeautifulSoup from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry import json import time catalog = {} def parse(): header = { 'user-agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.167 YaBrowser/22.7.5.940 Yowser/2.5 Safari/537.36" } session = requests.Session() retry = Retry(connect=1, backoff_factor=0.5) adapter = HTTPAdapter(max_retries=retry) # 挂载adapter到域名,而非单个URL,复用连接更高效 session.mount('http://foodmarkets.ru', adapter) inb = 1 comp = 'all' while inb <= 1: url_not_based = f"http://foodmarkets.ru/firms/filter_result/7/{comp}/0/posted/page{inb}/" r = session.get(url_not_based, verify=True, headers=header, timeout=5) soup = BeautifulSoup(r.text, "lxml") rounded_block = soup.find_all('tr') for row in rounded_block: # 提取公司名称:找到tcl类的td,再取其中a标签的文本 company_td = row.find('td', class_='tcl') if not company_td: continue company_name = company_td.find('a').get_text(strip=True).replace('\xa0', ' ') # 提取城市:直接取tc2 nowrap类td的文本 city_td = row.find('td', class_="tc2 nowrap") city_name = city_td.get_text(strip=True).replace('\xa0', ' ') if city_td else '' # 提取评论数:取tc2 cntr类td的文本 comment_td = row.find('td', class_="tc2 cntr") comment_count = comment_td.get_text(strip=True) if comment_td else '0' # 用公司名称作为键,避免Tag对象作为键的潜在问题 if company_name in catalog: continue catalog[company_name] = { "Company": company_name, "City": city_name, "Comment": comment_count, } inb += 1 time.sleep(0.5) print(catalog) with open("catalog.json", "w", encoding='utf-8') as file: json.dump(catalog, file, indent=4, ensure_ascii=False) if __name__ == "__main__": parse()
关键优化点
- 用
.get_text(strip=True)直接提取并清理文本,替代复杂正则,更可靠。 - 修复了
find方法的语法错误,正确定位元素。 - 将
session.mount挂载到域名而非单个URL,复用连接更高效。 - 用公司名称作为字典键,避免
bs4.element.Tag对象作为键的潜在问题。 - 增加了空值判断,避免因元素不存在导致的报错。
内容的提问来源于stack exchange,提问作者Apple
相关产品推荐
相关产品推荐

