关于部分网页p标签下嵌入随机不可见字符导致爬取的数据中包含大量无意义字符的解决办法:
示例网站:https://www.psychspace.com/psych/category-333
<p> <span style="display:none"> H1zZ y&}%pBD iluo</span> 剑桥大学发表的一项新的研究表明,父母和孩子之间的爱会显著增加孩子的 <a href="∠psych/action-tag-tagname-%C7%D7%C9%E7%BB%E1%D0%DO%CE%AA.html">亲社会行为</a> (prosociality)倾向、对他人表现出善意和同理心。这项研究使用了2000-02年间出生的10000多人的数据,以了解幼儿与父母的早期关系、亲社会性和心理健康之间的长期相互作用。 <span style="display:none">y&}%p H1z*&$(&%%jfjs</span> </p>
在上述html示例中,我需要的是p标签下的a标签中的text和p标签本身的text,过滤掉span标签下的无意义字符,最后拼接的效果期望如下:
剑桥大学发表的一项新的研究表明,父母和孩子之间的爱会显著增加孩子的亲社会行为(prosociality)倾向、对他人表现出善意和同理心。这项研究使用了2000-02年间出生的10000多人的数据,以了解幼儿与父母的早期关系、亲社会性和心理健康之间的长期相互作用。
几种解决方法和思路:
- re暴力过滤
这个思路是直接获取每一页的网页源代码,然后通过re.sub(r'<span\s+style="display:none">[^<]*</span>', '', text)
洗掉所有style="display:none"
的<span>
标签,然后就可以愉快地使用xpath、beautifulsoup等html解析库获取p标签下的列表进行字符串拼接啦。
import requests from lxml import etree text = ''' <p> <span style="display:none">ES"|#jed3dez)~a@ero</span> <a href="/psych/action-tag-tagname-%C8%CF%D6%AA%D0%D0%CE%AA%C1%C6%B7%A8.ht ml">认知行为疗法</a> "认为,抑郁症患者会出现「认知歪曲」的现象,这也是抑郁症的认知行为治疗中的一个关键挑战所在。“认知歪曲”会经常影响抑郁症患者的思维模式。其形式还包括仓促下结论、灾难化、非黑即白思维或自责,并可能给经历过这些的人带来如其所愿的痛苦。" <span style="display:none">心理学空间 g6HBa,_,tBz:f</span> </p> ''' # 清洗掉p标签下的span标签内的特殊字符 text2 = re.sub(r'<span\s+style="display:none">[^<]*</span>', '', text) # print(text2) html = etree.HTML(text2) texts = [] for p in html.xpath('//p'): text = ''.join(p.xpath('.//text()')) # 这里可以加一些字符串处理的过程 text = text.strip().replace('\n', '').replace('"', '') texts.append(text) result = ''.join(texts) print(result)
- xpath对p标签进行逐个解析
这个思路就是获取p标签下所有内容的字符串形式,然后写正则去掉不要的字符串就可以,主要用到html.xpath('//p/node()')
和etree.tostring()
两个方法。
import requests from lxml import etree url = 'https://www.example.com' response = requests.get(url) html = etree.HTML(response.text) # 获取p标签下的所有内容,包括标签和文本 contents = html.xpath('.//p/node()') output = '' for item in contents: output += etree.tostring(item, encoding='unicode') print(output)
.//p/node()
的 XPath 表达式可以获取到 <p>
标签下的所有节点,包括标签节点和文本节点。然后,我们通过遍历这些节点,并使用 etree.tostring()
方法将每个节点转换成字符串形式,并将其追加到 output
变量中。以上代码可<p>
标签下的所有内容组成的字符串output
,其中包括了标签和文本。
获取字符串形式的文本后,编写正则表达式进行文本的进一步清洗。
注意,<p>
标签内部可能包含其他标签,如果编写的正则表达式没有遍历所有情况,可能导致获取到的文本带有为过滤掉的其他标签(如<img>
、<video>
)。如果只想获取纯文本内容,可以考虑其他方法代替正则表达式,比如去除 HTML 标签的函数库(这个我也还没探索过)。
- xpath的remove函数
大致思路是先通过xpath定位到<p>
标签下的<span>
标签,然后使用getparent().remove(span)
代码删除了span标签。
text = ''' <p> <span style="display:none">ES"|#jed3dez)~a@ero</span> <a href="/psych/action-tag-tagname-%C8%CF%D6%AA%D0%D0%CE%AA%C1%C6%B7%A8.ht ml">认知行为疗法</a> "认为,抑郁症患者会出现「认知歪曲」的现象,这也是抑郁症的认知行为治疗中的一个关键挑战所在。“认知歪曲”会经常影响抑郁症患者的思维模式。其形式还包括仓促下结论、灾难化、非黑即白思维或自责,并可能给经历过这些的人带来如其所愿的痛苦。" <span style="display:none">心理学空间 g6HBa,_,tBz:f</span> </p> ''' # 解析HTML文本 html = etree.HTML(text) # 清洗掉p标签下的span标签内的特殊字符 for span in html.xpath('//p/span'): span.getparent().remove(span) # 提取a标签内的文本,拼接到p标签内的文本 texts = [] for p in html.xpath('//p'): text = ''.join(p.xpath('.//text()')).strip() # 去除开头结尾的换行符 text = re.sub(r'\s+|"', '', text) # 去除引号和空格 texts.append(text) result = ''.join(texts) print(result)