网页表格抓取( 【soup】新三板soup()进阶版(一))
优采云 发布时间: 2021-10-24 03:15网页表格抓取(
【soup】新三板soup()进阶版(一))
爬取最多的数据分析是表类型。需要专注于掌握。
本文介绍四种方法:
一、find_all 方法 (tr, td)
进行如下操作:
1、检查网页元素,观察
右键单击表单并选择“检查”。在弹出的“开发者工具”中,我们可以看到页面上的每个元素以及其中收录的内容。
可以看到每一行都是一个tr标签,每个内容都在tr下的td标签中。(可以做练习,但实际情况往往没有那么简单,这个页面的所有数据都显示在一个页面上。其实很多数据往往分布在多个不同的页面上,需要调整结果总数显示在每个页面上,或者遍历所有来捕获完整的数据。)
可以看到表格属性:table
2、连接获取网页内容,使用BeautifulSoup处理html数据
# 导入BeautifulSoup、urllib(request、urlopen)
from bs4 import BeautifulSoup as bs
import urllib
import urllib.request
from urllib.request import urlopen
import csv
urpage="https://www.fasttrack.co.uk/league-tables/tech-track-100/league-table/"
page = urlopen(urpage)
soup=bs(page,"html.parser")
可以使用print(soup)查看是否正确获取汤
如果打印出来,可以看到我们要查找的表中的th(表头)有8列。它们是等级、公司、位置等。
3、 遍历汤中的所有元素并将它们存储在变量中
存储可以使用空列表+设置标题+循环追加元素的方法
循环的结构很简单,主要部分如下(通过两个find_all,第一个tr list进行for循环,第二个td分截截取):
results=table.find_all('tr')
for result in results:
data=result.find_all("td")
loca=data[2].getText()
······
rows.append([rank, company, loca, yearend, anual_sales, sales, staff, comments])
完成如下:
## 空列表加表头
rows=[]
rows.append(["rank","company","loca","yearend","anual_sales","sales","staff","comments"])
## 循环存储
table=soup.find("table")
results=table.find_all('tr')
for result in results:
data=result.find_all("td")
if len(data)==0:
continue
rank=data[0].getText()
company=data[1].getText()
## 如需使用纯公司名,需处理成
## company=data[1].find("span",attrs={"class":"company-name"}).getText()
loca=data[2].getText()
yearend=data[3].getText()
anual_sales=data[4].getText()
sales=data[5].getText()
## 处理sales中符号
sales = sales.strip('*').strip('+').replace(',','')
staff=data[6].getText()
comments=data[7].getText()
rows.append([rank, company, loca, yearend, anual_sales, sales, staff, comments])
print(rows)
4、保存到csv
with open('techtrack100.csv','w', newline='',encoding="utf-8") as f_output:
csv_output = csv.writer(f_output)
csv_output.writerows(rows)
二、pandas 库中的 read_html 方法(表类型)
只需不到十行代码,约一分钟就能将4000多家A股上市公司的209页信息一网打尽。与正则表达式、xpath等常规方法相比,省心省力多了。
参数:io 可以是目标 URL,match 是要匹配的正则表达式,flavor 是解析器,header 是指定的行标题,encoding 是要读取的编码格式。只有设置正确才能正确提取表格,否则会出现乱码。
%s 代表页数;a:代表A股,用h代替a,代表港股;用xsb替换a,代表新的第三块板。
import pandas as pd
import csv
for i in range(1,178): # 爬取全部177页数据
url = 'http://s.askci.com/stock/a/?reportTime=2017-12-31&pageNum=%s' % (str(i))
tb = pd.read_html(url)[3] #经观察发现所需表格是网页中第4个表格,故为[3]
tb.to_csv(r'C:\Users\xxx\Desktop\1.csv', mode='a', encoding='utf_8_sig', header=1, index=0)
print('第'+str(i)+'页抓取完成')
完整的高级版本代码:
# 网页提取函数
def get_one_page(i):
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'
}
paras = {
'reportTime': '2019-12-31',
#可以改报告日期,比如2018-6-30获得的就是该季度的信息
'pageNum': i #页码
}
url = 'http://s.askci.com/stock/a/?' + urlencode(paras)
response = requests.get(url,headers = headers)
if response.status_code == 200:
return response.text
return None
except:
print('爬取失败')
# beatutiful soup解析然后提取表格
def parse_one_page(html):
soup = BeautifulSoup(html,'lxml')
content = soup.select('#myTable04')[0] #[0]将返回的list改为bs4类型
tbl = pd.read_html(content.prettify(),header = 0)[0]
# prettify()优化代码,[0]从pd.read_html返回的list中提取出DataFrame
tbl.rename(columns = {'序号':'serial_number', '股票代码':'stock_code', '股票简称':'stock_abbre', '公司名称':'company_name', '省份':'province', '城市':'city', '主营业务收入(201712)':'main_bussiness_income', '净利润(201712)':'net_profit', '员工人数':'employees', '上市日期':'listing_date', '招股书':'zhaogushu', '公司财报':'financial_report', '行业分类':'industry_classification', '产品类型':'industry_type', '主营业务':'main_business'},inplace = True)
print(tbl)
# return tbl
# rename将表格15列的中文名改为英文名,便于存储到mysql及后期进行数据分析
# tbl = pd.DataFrame(tbl,dtype = 'object') #dtype可统一修改列格式为文本
tbl.to_csv(r'C:\Users\xxx\Desktop\2.csv', mode='a',encoding='utf_8_sig', header=1, index=0)
# 主函数
def main(page):
for i in range(1,page): # page表示提取页数
html = get_one_page(i)
parse_one_page(html)
# 单进程
if __name__ == '__main__':
main(200) #共提取n页
快速方便,但缺点是无法读取单元格中的href链接。
三、selenium(可以被JavaScript动态抓取的表)
思路(Selenium基本是“可见,可爬取”):一次爬取所有td节点单元内容,按照表列数划分列表内容
1、 爬取所有td节点,按照表列数拆分成表
from selenium import webdriver
browser = webdriver.Firefox()
browser.get('http://data.eastmoney.com/bbsj/202009/yjbb.html')
element=browser.find_element_by_xpath('//div[@id="dataview"]')
# 提取表格内容td
td_content = element.find_elements_by_tag_name("td") # 进一步定位到表格内容所在的td节点
lst = [] # 存储为list
for td in td_content:
lst.append(td.text)
print(lst) # 输出表格内容
import pandas as pd
# 确定表格列数
col = len(element.find_elements_by_css_selector('tr:nth-child(1) td'))
# 通过定位一行td的数量,可获得表格的列数,然后将list拆分为对应列数的子list
lst = [lst[i:i + col] for i in range(0, len(lst), col)]
# list转为dataframe
df_table = pd.DataFrame(lst)
# 添加url列
# 原网页中打开"详细"链接可以查看更详细的数据,这里我们把url提取出来,方便后期查看
lst_link = []
links = element.find_elements_by_xpath("//a[contains(text(),'详细')]")
for link in links:
url = link.get_attribute('href')
lst_link.append(url)
lst_link = pd.Series(lst_link)
df_table['url'] = lst_link
print(df_table.head()) # 查看DataFrame
四、分析 URL JavaScript 请求
看
参考:
(这位“老农民工”博主写了很多优秀的文章)