selenium 将span标记替换为空白,或将内容解析为具有www.example.com _html的新列pandas.read

x0fgdtte  于 2022-11-24  发布在  其他
关注(0)|答案(2)|浏览(235)

我想从Capitol Trades中提取Congressional股票交易。我可以提取数据,但是包含股票行情代码的列有一个span标记,该标记将公司名称与公司行情代码分隔开。pandas.read_html()删除了此span标记,它将公司名称与股票行情代码连接在一起,使恢复股票行情代码变得困难。
例如,以“INC”后缀结尾的公司名称会出现在股票代码中,而股票代码也是大写字母。

下面是我找到span标记的位置:

公司股票代码的长度为1到5个字符,我未能正则化股票代码,因为公司后缀有很多种(eidogg.,“INC”,“CORP”,“PLC”,“SE”等),而且并不是所有的公司名称都有后缀。
如何用空格替换span标记以分隔公司名称和股票代码,或者如何将span解析为另一列?
下面是我的代码:

import pandas as pd
import yfinance as yf
from selenium import webdriver
from bs4 import BeautifulSoup
import time
import datetime

def get_url(page=1, pageSize=50, assetType='stock'):
    if page == 1:
        return f'https://www.capitoltrades.com/trades?assetType={assetType}&pageSize={pageSize}'
    elif page > 1:
        return f'https://www.capitoltrades.com/trades?assetType={assetType}&page={page}&pageSize={pageSize}'
    else:
        return None

driver = webdriver.Firefox()
driver.get(get_url(page=1))
driver.implicitly_wait(10)
time.sleep(1)
soup = BeautifulSoup(driver.page_source, 'lxml')
tables = soup.find_all('table')
table = pd.read_html(str(tables))[0]
driver.close()
jexiocij

jexiocij1#

要分离公司名称和股票代码,或者将span解析为另一列aka,以获得整体整洁干净的ResultSet,可以稍微改变一下工具选择策略。在这种情况下,最好使用apply bs4 with pandas DataFrame而不是pd.read_html()方法。

完整工作代码示例:

import pandas as pd
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from bs4 import BeautifulSoup
import time

driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
#The base url: https://www.capitoltrades.com/trades?assetType=stock&pageSize=50
data = []
for page in range(1, 5):
    driver.get(f'https://www.capitoltrades.com/trades?assetType=stock&pageSize=50&page={page}')
    driver.maximize_window()
    time.sleep(3)
    soup = BeautifulSoup(driver.page_source, 'lxml')
    for row in soup.select('table.q-table.trades-table > tbody tr'):
        Politician = row.select_one('[class="q-fieldset politician-name"] > a').text.strip()
        Politician_info = row.select_one('[class="q-fieldset politician-info"]').get_text(' ',strip=True)
        Traded_Issuer = row.select_one('[class="q-fieldset issuer-name"] > a').text.strip()
        Issuer_ticker =row.select_one('span[class="q-field issuer-ticker"]').text.strip()
        Published = row.select_one('[class="q-td q-column--pubDate"] .q-value').text.strip()
        Traded = row.select_one('[class="q-td q-column--txbDate"] .q-value')
        Traded = Traded.text.strip() if Traded else None
        Filed_after = row.select_one('[class="q-td q-column--reportingGap"] .q-value').text.strip()
        Owner =row.select_one('[class="svg-image owner-icon"]+span').text.strip()
        _type = row.select_one('[class="q-data-cell tx-type"]').get_text(strip=True)
        Size = row.select_one('[class="q-td q-column--value"] > div').get_text(strip=True)
        #Size = Size.text.strip() if Size else None
        Price =row.select_one('[class="q-field trade-price"]').text.strip()

        data.append({
            'Politician':Politician,
            'Politician_info':Politician_info,
            'Traded_Issuer':Traded_Issuer,
            'Issuer_ticker':Issuer_ticker,
            'Published':Published,
            'Traded':Traded,
            'Filed_after':Filed_after,
            'Owner':Owner,
            'Type':_type,
            'Size':Size,
            'Price':Price

        })

df = pd.DataFrame(data)
print(df)

输出:

Politician      Politician_info                 Traded_Issuer Issuer_ticker  ...        Owner  Type      Size   Price
0    Debbie Wasserman Schultz    Democrat House FL  ADAMS RESOURCES & ENERGY INC         AE:US  ...        Child  sell  1K - 15K   32.27     
1               Kathy Manning    Democrat House NC                         3M Co        MMM:US  ...       Spouse   buy  1K - 15K  108.95     
2               Kathy Manning    Democrat House NC                 Accenture PLC        ACN:US  ...       Spouse   buy  1K - 15K  250.07     
3               Kathy Manning    Democrat House NC                     Adobe Inc       ADBE:US  ...       Spouse  sell  1K - 15K  286.15     
4               Kathy Manning    Democrat House NC                  Alphabet Inc      GOOGL:US  ...       Spouse   buy  1K - 15K   97.56     
..                        ...                  ...                           ...           ...  ...          ...   ...       ...     ...       
195         Diana Harshbarger  Republican House TN                 CME Group Inc        CME:US  ...        Joint  sell  1K - 15K  176.26       
196         Diana Harshbarger  Republican House TN                 CME Group Inc        CME:US  ...       Spouse  sell  1K - 15K  176.26       
197         Diana Harshbarger  Republican House TN            The Home Depot Inc         HD:US  ...  Undisclosed  sell  1K - 15K  268.69       
198         Diana Harshbarger  Republican House TN            The Home Depot Inc         HD:US  ...  Undisclosed  sell  1K - 15K  268.69       
199         Diana Harshbarger  Republican House TN            The Home Depot Inc         HD:US  ...        Joint  sell  1K - 15K  268.69       

[200 rows x 11 columns]
ecbunoof

ecbunoof2#

顺便说一句,对于soupfind_all,您不需要执行这些步骤 - read_html已经使用了与bs 4相同[或者至少非常相似]的解析器,因此您可以只使用

table = pd.read_html(driver.page_source)[0] # , flavor='lxml')[0] # default

或者甚至直接pd.read_html(get_url(page=1))-它并不总是对所有页面都有效,但是它似乎对your页面有效;它不允许我将要建议的解决方案,但我认为值得一提的是,如果你还不知道这种便利性。
无论如何,我的第一个解决方案看起来有点笨拙,但到目前为止它对我来说是有效的-因为read_html似乎不像bs 4的get_text那样有任何字符串分隔符参数,我们可以尝试通过使用.replace在html中的每个标签的末尾添加空格来创建相同的效果。

table = pd.read_html(driver.page_source.replace('</', '&nbsp;</'))

如果你担心在html字符串上使用text-replace会造成混乱,或者担心添加不需要的空格(尽管据我所知,它 * 没有 *),或者只是想更多地控制文本从表格单元格中提取的方式,你也可以使用get_text [带空格(' ')分隔符]和list comprehension将bs 4 table标记转换为python字典。

tableSoup = soup.find('table')
tableHeaders = [
    h.get_text(' ', strip=True)
    for h in tableSoup.select('thead tr th')
]
tableData = [{h: c.get_text(' ', strip=True) for h, c in zip(
    tableHeaders, [cell for cell in r.select('td')]
)} for r in tableSoup.select('tbody tr')]
table = pd.DataFrame(tableData)

如果您想要自定义提取和/或处理单元格值的方式,甚至可以用自己的函数替换get_text,但实际上,它[以及带有.replace的第一个方法]创建的DataFrame如下所示:
| 政治家|交易发行人|已发布|已交易|归档于|所有者|型号|尺寸大小|标价|
| - -|- -|- -|- -|- -|- -|- -|- -|- -|
| 德克萨斯州共和党众议院议员皮特·塞申斯|美国国库票据N/A|昨天14:05| 2022年11月9日|第1天|未公开|购买|1万5千至5万|不适用|
| 德克萨斯州共和党众议院议员皮特·塞申斯|美国国库票据N/A|昨天14:05| 2022年11月7日|第3天|未公开|购买|5万至10万|不适用|
| 德克萨斯州共和党众议院议员皮特·塞申斯|美国国库票据N/A|昨天14:05| 2022年11月7日|第3天|未公开|购买|1千至15千|不适用|
| 布拉德·谢尔曼民主党众议院|美国国库票据N/A|昨天14:05| 2022年11月3日|第7天|未公开|出售|25万至50万|不适用|
| 布拉德·谢尔曼民主党众议院|美国国库票据N/A|昨天14:05| 2022年11月3日|第7天|未公开|出售|50万至1百万|不适用|
| 布拉德·谢尔曼民主党众议院|美国国库票据N/A|昨天14:05| 2022年11月3日|第7天|未公开|出售|25万至50万|不适用|
| 布拉德·谢尔曼民主党众议院|美国国库票据N/A|昨天14:05| 2022年11月7日|第3天|未公开|出售|25万至50万|不适用|
| 布拉德·谢尔曼民主党众议院|美国国库票据N/A|昨天14:05| 2022年11月3日|第7天|未公开|出售|25万至50万|不适用|
| 布拉德·谢尔曼民主党众议院|美国国库票据N/A|昨天14:05| 2022年11月3日|第7天|未公开|出售|1万5千至5万|不适用|
| 佛罗里达州众议院民主党人黛比·沃瑟曼·舒尔茨|亚当斯资源与能源公司AE:US|昨天14:05| 2022年10月27日|第14天|子项|出售|1千至15千|三十二点二十七分|
| 凯西·曼宁民主党众议员|3 M公司MMM:美国|昨天14:05| 2022年10月12日|第29天|配偶|购买|1千至15千|一百零八点九十五|
| 凯西·曼宁民主党众议员|埃森哲公司ACN:美国|昨天14:05| 2022年10月12日|第29天|配偶|购买|1千至15千|二百五十零七|
| 凯西·曼宁民主党众议员|Adobe公司ADBE:美国|昨天14:05| 2022年10月12日|第29天|配偶|出售|1千至15千|二百八十六点一五|
| 凯西·曼宁民主党众议员|字母公司GOOGL:US|昨天14:05| 2022年10月12日|第29天|配偶|购买|1千至15千|九十七点五六|
| 凯西·曼宁民主党众议员|Amazon.comAMZN:美国|昨天14:05| 2022年10月12日|第29天|配偶|购买|1千至15千|一百一十二点九|
[上表的Markdown是从print(table.drop([''], 'columns').to_markdown(index=False))的输出中复制的。]

相关问题