有什么方便的方法可以通过 python 中应用于它们的 ccs 样式来解析 html 元素?
Is there any convenient way to parse html elements by ccs styles applied to them in python?
我知道我可以使用 css 选择器和 bs4 等库来提取元素。但我有一个问题,我不知道 css 类 的名称用于设置我需要提取的元素的样式,但我知道所有这些元素都应用了通用规则(“position:fixed ;" 在我的例子中)。有什么方便的方法(一些库)可以用来做这个吗?
Selenium 是一个非常好的 python 自动化库,但它允许使用其 CSS 选择器等进行网页抓取和选择多个。这应该允许您使用
存储所有元素
("position:fixed;" in my case)
使用 selenium,您将能够提取数据,然后您可以随心所欲地操作数据。有很多方法可以解析数据本身,所以请更具体地说明那部分。
如果有疑问,请将网站 link 作为评论发送,我会为您检查 CSS 选择器。
希望这已经解决了问题。
除非 HTML 源具有内联样式,否则您将无法轻易确定每个元素具有哪些样式规则,从而使过滤过程更加复杂。下面的解决方案分为两部分:
- 从目标页面的源中,使用
tinycss
请求和解析 CSS 样式表。
- 然后,网站在
selenium
中打开,json
化的样式规则通过 driver.execute_script
传递给 Javascript 片段,即 运行 .这样,可以利用内置 Javascript 方法 element.matches
在 CSS 路径匹配检测中产生实质性加速:
import requests, urllib.parse, tinycss
import itertools
from bs4 import BeautifulSoup as soup
base_url = 'https://whosebug.com/questions/tagged/python' #replace with your own target link
def css(link):
parser = tinycss.make_parser('page3')
stylesheet = parser.parse_stylesheet(requests.get(link).text)
return [[i.selector.as_css(), [[j.name, j.value.as_css()] for j in i.declarations]]
for i in stylesheet.rules if not isinstance(i, tinycss.css21.MediaRule)]
css_links = [css(urllib.parse.urljoin(base_url, i['href'])) for i in \
soup(requests.get(base_url).text, 'html.parser').select('link[rel="stylesheet"]')]
现在,加载目标页面 selenium
:
from selenium import webdriver
import re, json
d = webdriver.Chrome('/path/to/chromedriver')
d.get(base_url)
rules = ['position:fixed', 'text-align: left'] #your rule list
new_rules = [re.split('\:(?:\s+)*', i) for i in rules]
classes = d.execute_script('''
var target_rules = JSON.parse(arguments[0]);
var selectors = JSON.parse(arguments[1]);
function* matching_rules(elem){
for (var i of selectors){
for (var [s, rules] of i){
try{
if (elem.matches(s)){
yield* rules
}
}
catch(e){
}
}
}
}
function* get_classes(elem){
if (elem.getAttribute('class')){
for (var rule of matching_rules(elem)){
if (target_rules.map(JSON.stringify).includes(JSON.stringify(rule))){
yield [elem.getAttribute('class'), rule]
}
}
}
for (var i of elem.children){
yield* get_classes(i);
}
}
return [...get_classes(document.querySelector('body'))]
''', json.dumps(new_rules), json.dumps(css_links))
print(classes)
输出:
[['top-bar js-top-bar top-bar__network', ['position', 'fixed']], ['topbar-dialog leftnav-dialog js-leftnav-dialog dno', ['text-align', 'left']], ['s-spinner s-spinner__sm fc-orange-400', ['text-align', 'left']], ['topbar-dialog siteSwitcher-dialog dno', ['text-align', 'left']], ['container', ['text-align', 'left']], ['left-sidebar--sticky-container js-sticky-leftnav', ['position', 'fixed']], ['mln12 mrn12 px12 py6 fl1 s-block-link', ['text-align', 'left']], ['mln12 mrn12 px12 py6 fl1 s-block-link', ['text-align', 'left']], ['mln12 mrn12 px12 py6 fl1 s-block-link', ['text-align', 'left']], ['mln12 mrn12 px12 py6 fl1 s-block-link', ['text-align', 'left']], ['s-block-link c-default fc-black-350 mln12 mrn12 px12 py6', ['text-align', 'left']], ['s-modal js-feed-link-modal', ['position', 'fixed']], ['ff-sans ps-fixed z-nav-fixed ws4 sm:w-auto p32 sm:p16 bg-black-750 fc-white bar-lg b16 l16 r16 js-consent-banner', ['position', 'fixed']]]
输出包含class所有具有目标规则集中样式规则的元素的名称。
如果您想获得与每个样式规则关联的唯一 class 名称,您可以使用 collections.defaultdict
:
from collections import defaultdict
d = defaultdict(set)
for c_name, rule in classes:
d[tuple(rule)].add(c_name)
print({a:list(b) for a, b in d.items()})
输出:
{('position', 'fixed'): ['left-sidebar--sticky-container js-sticky-leftnav', 's-modal js-feed-link-modal', 'ff-sans ps-fixed z-nav-fixed ws4 sm:w-auto p32 sm:p16 bg-black-750 fc-white bar-lg b16 l16 r16 js-consent-banner', 'top-bar js-top-bar top-bar__network'], ('text-align', 'left'): ['s-spinner s-spinner__sm fc-orange-400', 'mln12 mrn12 px12 py6 fl1 s-block-link', 'topbar-dialog siteSwitcher-dialog dno', 's-block-link c-default fc-black-350 mln12 mrn12 px12 py6', 'topbar-dialog leftnav-dialog js-leftnav-dialog dno', 'container']}
我知道我可以使用 css 选择器和 bs4 等库来提取元素。但我有一个问题,我不知道 css 类 的名称用于设置我需要提取的元素的样式,但我知道所有这些元素都应用了通用规则(“position:fixed ;" 在我的例子中)。有什么方便的方法(一些库)可以用来做这个吗?
Selenium 是一个非常好的 python 自动化库,但它允许使用其 CSS 选择器等进行网页抓取和选择多个。这应该允许您使用
存储所有元素("position:fixed;" in my case)
使用 selenium,您将能够提取数据,然后您可以随心所欲地操作数据。有很多方法可以解析数据本身,所以请更具体地说明那部分。 如果有疑问,请将网站 link 作为评论发送,我会为您检查 CSS 选择器。 希望这已经解决了问题。
除非 HTML 源具有内联样式,否则您将无法轻易确定每个元素具有哪些样式规则,从而使过滤过程更加复杂。下面的解决方案分为两部分:
- 从目标页面的源中,使用
tinycss
请求和解析 CSS 样式表。 - 然后,网站在
selenium
中打开,json
化的样式规则通过driver.execute_script
传递给 Javascript 片段,即 运行 .这样,可以利用内置 Javascript 方法element.matches
在 CSS 路径匹配检测中产生实质性加速:
import requests, urllib.parse, tinycss
import itertools
from bs4 import BeautifulSoup as soup
base_url = 'https://whosebug.com/questions/tagged/python' #replace with your own target link
def css(link):
parser = tinycss.make_parser('page3')
stylesheet = parser.parse_stylesheet(requests.get(link).text)
return [[i.selector.as_css(), [[j.name, j.value.as_css()] for j in i.declarations]]
for i in stylesheet.rules if not isinstance(i, tinycss.css21.MediaRule)]
css_links = [css(urllib.parse.urljoin(base_url, i['href'])) for i in \
soup(requests.get(base_url).text, 'html.parser').select('link[rel="stylesheet"]')]
现在,加载目标页面 selenium
:
from selenium import webdriver
import re, json
d = webdriver.Chrome('/path/to/chromedriver')
d.get(base_url)
rules = ['position:fixed', 'text-align: left'] #your rule list
new_rules = [re.split('\:(?:\s+)*', i) for i in rules]
classes = d.execute_script('''
var target_rules = JSON.parse(arguments[0]);
var selectors = JSON.parse(arguments[1]);
function* matching_rules(elem){
for (var i of selectors){
for (var [s, rules] of i){
try{
if (elem.matches(s)){
yield* rules
}
}
catch(e){
}
}
}
}
function* get_classes(elem){
if (elem.getAttribute('class')){
for (var rule of matching_rules(elem)){
if (target_rules.map(JSON.stringify).includes(JSON.stringify(rule))){
yield [elem.getAttribute('class'), rule]
}
}
}
for (var i of elem.children){
yield* get_classes(i);
}
}
return [...get_classes(document.querySelector('body'))]
''', json.dumps(new_rules), json.dumps(css_links))
print(classes)
输出:
[['top-bar js-top-bar top-bar__network', ['position', 'fixed']], ['topbar-dialog leftnav-dialog js-leftnav-dialog dno', ['text-align', 'left']], ['s-spinner s-spinner__sm fc-orange-400', ['text-align', 'left']], ['topbar-dialog siteSwitcher-dialog dno', ['text-align', 'left']], ['container', ['text-align', 'left']], ['left-sidebar--sticky-container js-sticky-leftnav', ['position', 'fixed']], ['mln12 mrn12 px12 py6 fl1 s-block-link', ['text-align', 'left']], ['mln12 mrn12 px12 py6 fl1 s-block-link', ['text-align', 'left']], ['mln12 mrn12 px12 py6 fl1 s-block-link', ['text-align', 'left']], ['mln12 mrn12 px12 py6 fl1 s-block-link', ['text-align', 'left']], ['s-block-link c-default fc-black-350 mln12 mrn12 px12 py6', ['text-align', 'left']], ['s-modal js-feed-link-modal', ['position', 'fixed']], ['ff-sans ps-fixed z-nav-fixed ws4 sm:w-auto p32 sm:p16 bg-black-750 fc-white bar-lg b16 l16 r16 js-consent-banner', ['position', 'fixed']]]
输出包含class所有具有目标规则集中样式规则的元素的名称。
如果您想获得与每个样式规则关联的唯一 class 名称,您可以使用 collections.defaultdict
:
from collections import defaultdict
d = defaultdict(set)
for c_name, rule in classes:
d[tuple(rule)].add(c_name)
print({a:list(b) for a, b in d.items()})
输出:
{('position', 'fixed'): ['left-sidebar--sticky-container js-sticky-leftnav', 's-modal js-feed-link-modal', 'ff-sans ps-fixed z-nav-fixed ws4 sm:w-auto p32 sm:p16 bg-black-750 fc-white bar-lg b16 l16 r16 js-consent-banner', 'top-bar js-top-bar top-bar__network'], ('text-align', 'left'): ['s-spinner s-spinner__sm fc-orange-400', 'mln12 mrn12 px12 py6 fl1 s-block-link', 'topbar-dialog siteSwitcher-dialog dno', 's-block-link c-default fc-black-350 mln12 mrn12 px12 py6', 'topbar-dialog leftnav-dialog js-leftnav-dialog dno', 'container']}