BeautifulSoup 根据输入的公司名称来爬取公司的详细信息(2022-08-24更新版)

BeautifulSoup 根据输入的公司名称来爬取公司的详细信息----2022-08-24更新版

  • 因为有不少博友私信我除了工商信息板块,其他板块的信息能不能也处理一下,所以我抽空新增了一下功能,对于爬取的整体页面,进行更多的信息处理。
  • 在此强烈声明,本笔记仅用于个人学习用途,提供一些关于BeautifulSoup的用法和数据预处理的思路,并不支持大量数据的爬取,如果大家想爬取数据量大的公司群体,建议自学一下代理池和并行运行等方面的知识。

1、获取headers

1、进入qcc官网进行注册并登录。
2、然后按F12弹出开发者工具,点击Network,然后你会看到企查查这个网址,点击一下
在这里插入图片描述

然后可以找到我们需要复制的header(User-Agent与cookie),这是非常关键的步骤,切记这个header(User-Agent与cookie)是自己注册之后登录成功所获取的header(User-Agent与cookie),这样方便后面保存一次之后就可以在一定时间内无限访问网址进行查询的操作。
在这里插入图片描述
在这里插入图片描述

from bs4 import BeautifulSoup
import requests
import time
import pandas as pd
from requests.auth import HTTPBasicAuth
import os
import xlwings as xw
import re

# 保持会话
# 新建一个session对象
sess = requests.session()

# 添加headers(header为自己登录的企查查网址,输入账号密码登录之后所显示的header,此代码的上方介绍了获取方法)
afterLogin_headers = {'User-Agent': '此代码上方介绍了获取的方法','cookie':'此代码上方介绍了获取的方法'}

# 以用户的身份认证,方便后面执行查询指令
from requests.auth import HTTPBasicAuth
res = requests.get('https://www.qcc.com/',headers=afterLogin_headers, auth=HTTPBasicAuth('qcc登录成功后的用户名', '登录成功后的qcc密码'))
print(res.status_code)

整段代码的含义为:伪装成用户进行登录行为(返回200状态码代表着登录成功)。有些人爬不到信息,很可能是自己的账号密码不对,或者自己复制的User-Agent以及cookie不对,如果不知道自己写的对不对,执行一下下面这个代码则可证明:

# 测试所用,在上面那一段代码执行完后,为了验证自己有无登录企查查成功,可随意爬取某个网页并显示是否有正确对应的内容。
# 获取查询到的网页内容(全部)
search = sess.get('https://www.qcc.com/web/search?key={}'.format('腾讯'),headers=afterLogin_headers, auth=HTTPBasicAuth('企查查登录成功后的用户名', '登录成功后的企查查密码'), timeout=10)
search.raise_for_status()
search.encoding = 'utf-8' #linux utf-8
soup = BeautifulSoup(search.text,features="html.parser")
print(soup)

2、登录成功后,可根据输入的公司名称进行查询操作,得到所需要的内容。

# 获取特定公司的指定信息
def get_company_message(company, afterLogin_headers):
    # 获取查询到的网页内容(全部)
    search = sess.get('https://www.qcc.com/web/search?key={}'.format(company),headers=afterLogin_headers,timeout=10)
    search.raise_for_status()
    search.encoding = 'utf-8' #linux utf-8
    soup = BeautifulSoup(search.text,features="html.parser")
    href = soup.find_all('a',{'class': 'title'})[0].get('href')
    target_company = soup.find_all('a',{'class': 'title'})[0].text
    time.sleep(4)
    details = sess.get(href,headers=afterLogin_headers,timeout=10)
    details.raise_for_status()
    details.encoding = 'utf-8' #linux utf-8
    details_soup = BeautifulSoup(details.text,features="html.parser")
    # 获取企业主页
    conpany_homePage = details_soup.find_all('div',{'class': 'content'})[0]
    # 获取工商信息
    business_message = details_soup.find_all({'table': 'ntable'})[0].text
    # 获取股东信息
    try:
        partner_message = details_soup.find_all(id=re.compile('partner'))[0].select('table')
        # 如果列表为空,则代表改信息只有vip账号才能获取,设置为0跳过处理
        if partner_message==[]:
            partner_message = 0
    except:
        partner_message = 0 
    # 获取主要人员
    try:
        main_people = details_soup.find_all(id='mainmember')[0].select('table')
        # 如果列表为空,则代表改信息只有vip账号才能获取,设置为0跳过处理
        if main_people==[]:
            main_people = 0
    except:
        main_people = 0
    # 获取对外投资
    try:
        external_touzi = details_soup.find_all(id=re.compile('touzilist'))[0].select('table')
        # 如果列表为空,则代表改信息只有vip账号才能获取,设置为0跳过处理
        if external_touzi==[]:
            external_touzi = 0
    except:
        external_touzi = 0
    # 获取变更记录
    try:
        change_record = details_soup.find_all(id=re.compile('changelist'))[0].select('table')
        if change_record == []:
            change_record = 0
    except:
        change_record = 0
    
    return [target_company,conpany_homePage, business_message, partner_message, main_people, external_touzi, change_record]

上面的函数get_company_message(),函数如其名,是为了获取公司的文本信息。总体上包括着三个步骤。

  • ①查询某公司
  • ②点击进入第一位搜索结果的新网站
  • ③获取该搜索结果中关于企业主页、工商信息、股东信息、主要人员、对外投资、变更记录等这些卡片的网页信息,其他卡片的网页信息据我观察大部分都需要vip,我没有vip账号,所以不对这些板块进行信息处理
    在这里插入图片描述
    在这里插入图片描述

3、将获取到的表格内容进行文本特殊化处理,并将其汇总成一个dataframe,方便后面保存为csv

3.1、将企业主页头部的信息转化为dataframe

# 获取企业主页头部的信息
def conpany_homePage_to_df(company_name,company_message):
    if company_message==0:
        homePage_df = pd.DataFrame()
    else:
        company_content = company_message.find_all('div', {'class': 'contact-info'})[0].text.replace("\n", "").replace(" ", "")
        # 法定代表人
        try:
            c1 = company_content.split("法定代表人:")[1].split('关联')[0]
        except:
            c1 = '无'
        # 统一社会信用代码
        try:
            c2 = company_content.split("统一社会信用代码:")[1].split("复制")[0]
        except:
            c2 = '无'
        # 电话
        c3 = company_content.split("电话:")[1].split("同电话")[0].split("更多")[0]
        # 官网
        c4 = company_content.split("官网:")[1].split("邮箱")[0]
        # 邮箱
        c5 = company_content.split("邮箱:")[1].split("复制")[0]
        # 地址
        c6 = company_content.split("地址:")[1].split("附近企业")[0]
        # 简介
        c7 = company_content.split("简介:")[1].split("复制")[0]

        homePage_df = pd.DataFrame({'公司名称': [company_name],'法定代表人': [c1],'统一社会信用代码': [c2],\
            '电话': [c3], '官网': [c4], '邮箱': [c5], '地址': [c6], '简介': [c7]})
        
    return homePage_df

在这里插入图片描述

3.2、将工商信息版块的信息转化为dataframe

import pandas as pd

# 获取工商信息的卡片
def business_message_to_df(message):
    # 统一社会信用代码
    unified_social_credit_code = []
    try:
        unified_social_credit_code.append(message.split('统一社会信用代码')[1].split('复制')[0].replace(" ","").replace("\n",""))
    except:
        unified_social_credit_code.append('无法收集')
    # 企业名称
    list_companys = []
    try:
        list_companys.append(message.split('企业名称')[1].split('复制')[0].replace(" ","").replace("\n",""))
    except:
        list_companys.append('无法收集')
    # 法定代表人
    Legal_Person = []
    try:
        Legal_Person.append(message.split('法定代表人')[1].split('关联')[0].replace("\n","").replace(" ",""))
    except:
        Legal_Person.append('无法收集')
    # 登记状态
    Registration_status = []
    try:
        Registration_status.append(message.split('登记状态')[1].split('成立日期')[0].replace(" ","").replace("\n",""))
    except:
        Registration_status.append('无法收集')
    # 成立日期
    Date_of_Establishment = []
    try:
        Date_of_Establishment.append(message.split('成立日期')[1].split('注册资本')[0].replace(" ","").replace("\n",""))
    except:  
        Date_of_Establishment.append('无法收集')
    # 注册资本
    registered_capital = []
    try:
        registered_capital.append(message.split('注册资本')[1].split('实缴资本')[0].replace(' ','').replace("\n",""))
    except:
        registered_capital.append('无法收集')
    # 实缴资本
    contributed_capital = []
    try:
        contributed_capital.append(message.split('实缴资本')[1].split('核准日期')[0].replace(' ','').replace('\n',''))
    except:
        contributed_capital.append('无法收集')
    # 核准日期
    Approved_date = []
    try:
        Approved_date.append(message.split('核准日期')[1].split('组织机构代码')[0].replace(' ','').replace("\n",""))
    except:
        Approved_date.append('无法收集')
    # 组织机构代码
    Organization_Code = []
    try:
        Organization_Code.append(message.split('组织机构代码')[1].split('复制')[0].replace(' ','').replace("\n",""))
    except:
        Organization_Code.append('无法收集')
    # 工商注册号
    companyNo = []
    try:
        companyNo.append(message.split('工商注册号')[1].split('复制')[0].replace(' ','').replace("\n",""))
    except:
        companyNo.append('无法收集')
    # 纳税人识别号
    Taxpayer_Identification_Number = []
    try:
        Taxpayer_Identification_Number.append(message.split('纳税人识别号')[1].split('复制')[0].replace(' ','').replace("\n",""))
    except:
        Taxpayer_Identification_Number.append('无法收集')
    # 企业类型
    enterprise_type = []
    try:
        enterprise_type.append(message.split('企业类型')[1].split('营业期限')[0].replace('\n','').replace(' ',''))
    except:
        enterprise_type.append('无法收集')
    # 营业期限
    Business_Term = []
    try:
        Business_Term.append(message.split('营业期限')[1].split('纳税人资质')[0].replace('\n','').replace(' ',''))
    except:
        Business_Term.append('无法收集')
    # 纳税人资质
    Taxpayer_aptitude = []
    try:
        Taxpayer_aptitude.append(message.split('纳税人资质')[1].split('所属行业')[0].replace(' ','').replace("\n",""))
    except:
        Taxpayer_aptitude.append('无法收集')
    # 所属行业
    sub_Industry = []
    try:
        sub_Industry.append(message.split('所属行业')[1].split('所属地区')[0].replace('\n','').replace(' ',''))
    except:
        sub_Industry.append('无法收集')   
    # 所属地区
    sub_area = []
    try:
        sub_area.append(message.split('所属地区')[1].split('登记机关')[0].replace(' ','').replace("\n",""))
    except:
        sub_area.append('无法收集')
    # 登记机关
    Registration_Authority = []
    try:
        Registration_Authority.append(message.split('登记机关')[1].split('人员规模')[0].replace(' ','').replace("\n",""))
    except:
        Registration_Authority.append('无法收集')
    # 人员规模
    staff_size = []
    try:
        staff_size.append(message.split('人员规模')[1].split('参保人数')[0].replace(' ','').replace('\n',''))
    except:
        staff_size.append('无法收集')
    # 参保人数
    Number_of_participants = []
    try:
        Number_of_participants.append(message.split('参保人数')[1].split('趋势图')[0].replace(' ','').replace("\n",""))
    except:
        Number_of_participants.append('无法收集')
    # 曾用名
    Used_Name = []
    try:
        Used_Name.append(message.split('曾用名')[1].split('英文名')[0].replace(' ','').replace("\n",""))
    except:
        Used_Name.append('无法收集')
    # 英文名
    English_name = []
    try:
        English_name.append(message.split('英文名')[1].split('进出口企业代码')[0].replace('\n','').replace(' ',''))
    except:
        English_name.append('无法收集')
    # 进出口企业代码
    import_and_export_code = []
    try:
        import_and_export_code.append(message.split('进出口企业代码')[1].split('复制')[0].replace(' ','').replace("\n",""))
    except:
        import_and_export_code.append('无法收集')
    # 注册地址
    register_adress = []
    try:
        register_adress.append(message.split('注册地址')[1].split('附近企业')[0].replace(' ','').replace("\n",""))
    except:
        register_adress.append('无法收集')
    # 经营范围
    Business_Scope = []
    try:
        Business_Scope.append(message.split('经营范围')[1].replace(' ','').replace("\n",""))
    except:
        Business_Scope.append('无法收集')
    df = pd.DataFrame({'统一社会信用代码': unified_social_credit_code,\
                       '企业名称': list_companys,\
                       '法定代表人':Legal_Person,\
                      '登记状态':Registration_status,\
                      '成立日期':Date_of_Establishment,\
                      '注册资本':registered_capital,\
                      '实缴资本':contributed_capital,\
                      '核准日期':Approved_date,\
                      '组织机构代码':Organization_Code,\
                      '工商注册号':companyNo,\
                      '纳税人识别号':Taxpayer_Identification_Number,\
                      '企业类型':enterprise_type,\
                      '营业期限':Business_Term,\
                      '纳税人资质':Taxpayer_aptitude,
                      '所属行业':sub_Industry,\
                      '所属地区':sub_area,\
                      '登记机关':Registration_Authority,\
                      '人员规模':staff_size,\
                      '参保人数':Number_of_participants,\
                      '曾用名': Used_Name, \
                      '英文名':English_name, \
                      '进出口企业代码': import_and_export_code, \
                      '注册地址':register_adress,\
                      '经营范围':Business_Scope})
    
    return df
    

这段代码是对爬取到的表格的文本内容进行文本识别处理,只适合于表格格式为2中第二张图片这样的,如果出现 “无法收集” 这个值,很有可能是因为该值不存在于爬取的表格文本中。
在这里插入图片描述

3.3、将除了上面两个之外其他版本的网页信息转化为dataframe

# 获取列名为横向的卡片信息
def col_is_vertical_to_df(company_name,message):
    if message==0:
        col_df = pd.DataFrame()
    else:
        # 定位到你要的那个表格,靠id=特定id,然后再在这个基础上找到table标签
        list_col = []
        list_row_all = []
        # 获取列名
        col_name = message[0].select('tr')[0].select('th')
        for i in range(len(col_name)):
            list_col.append(col_name[i].text.replace(' ','').replace('\n',''))
        # 获取每一行的信息
        row = len(message[0].select('tr'))-1
        for i in range(row):
            list_row = []
            col_i = message[0].select('tr')[i+1].select('td')
            for i in range(len(col_i)):
                list_row.append(col_i[i].text.replace(' ','').replace('\n','').split('关联')[0])
            list_row_all.append(list_row)
        # 汇总为dataframe
        col_df = pd.DataFrame(list_row_all, columns=list_col)
        col_df['公司名称'] = company_name
    return col_df

因为其他板块的信息基本都是这种格式:
在这里插入图片描述

所以可以用同一个函数处理并汇总成dataframe

4、为了便于阅读,我写了三个关于xlsx文件的处理函数

4.1、对于规则的列进行无列名合并

# 对于有规则的固定列,授予专门的处理函数
def regular_line(app, sheet_name, df):
    if len(df) == 0:
        pass
    else:
        # 给对应工作表添加内容
        sheet = app.sheets[sheet_name]

        # 获取工作表目前的行
        if sheet.used_range.rows.count == 1:
            now_row = sheet.used_range.rows.count
            # 将dataframe的数据写进xlsx
            sheet.range('A' + str(now_row)).options(pd.DataFrame, expand='table', index=False).value = df
            sheet.range('A1').expand('right').api.Font.Bold = True
        else:
            now_row = sheet.used_range.rows.count + 1
            # 将dataframe的数据写进xlsx
            sheet.range('A' + str(now_row)).options(pd.DataFrame, expand='table',header=False,index=False).value = df

在这里插入图片描述

4.2、对于不规则的列进行列名合并

# 对于无规则的固定列,授予专门的处理函数
def Irregular_line(app, sheet_name, df):
    if len(df) == 0:
        pass
    else:
        # 给对应工作表添加内容
        sheet = app.sheets[sheet_name]

        # 获取工作表目前的行
        if sheet.used_range.rows.count == 1:
            now_row = sheet.used_range.rows.count
        else:
            now_row = sheet.used_range.rows.count + 2
        # 将dataframe的数据写进xlsx
        sheet.range('A' + str(now_row)).options(pd.DataFrame, expand='table', index=False).value = df

        # 将列名那一行上黄色,然后数据行上灰色
        for i in range(len(df2)+1):
            if i == 0:
                sheet.range('A' + str(now_row)).expand('right').color = (255,255,0)
            else:
                sheet.range('A' + str(now_row+i)).expand('right').api.Font.Color = 0x00000 
                sheet.range('A' + str(now_row+i)).expand('right').color = (220,220,220)

在这里插入图片描述

4.3、对于因为图片带有姓的原因造成姓重复的情况,进行去重

# 对于因为图片带有姓的原因造成姓重复的情况,进行去重,此函数只适合于大部分情况
def dedup_name(origin_name):
    if len(origin_name)>=2:
        if(origin_name[0:1] == origin_name[1:2]):
            target_name = origin_name[1:]
        else:
            target_name = origin_name
    target_name = target_name.replace('最终受益人','').replace('实际控制人','').replace('大股东','').replace('有限制','').replace('高消费','')
    
    return target_name

在这里插入图片描述

5、输入公司名称

  • 这里只是写个案例,所以随便写了个列表,一般跑自己代码的是读取自己的csv文件关于公司名称的那一列,然后转为列表)
# 测试所用
companys = ['深圳市腾讯计算机系统有限公司','阿里巴巴(中国)有限公司']

# 实际所用
# df_companys = pd.read_csv('自己目录的绝对路径/某某.csv')
# companys = df_companys['公司名称'].tolist()

5、最后执行此代码,查询companys列表中所有公司名称的详细信息并保存为csv。

save_path = '自己目录的绝对路径/某某.csv'
# 获取列表中的每一个公司的信息
app = xw.App(visible=False)
try:
    for i in range(len(companys)):

        # 获取该公司的部分网页信息
        company_message = get_company_message(companys[i],afterLogin_headers)
        # 企业主页 
        df1 = conpany_homePage_to_df(company_message[0],company_message[1])
        # 工商信息 
        df2 = business_message_to_df(company_message[2])
        df2['法定代表人'] = df2['法定代表人'].apply(dedup_name)
        # 股东信息 
        df3 = col_is_vertical_to_df(company_message[0],company_message[3])
        # 主要人员
        df4 = col_is_vertical_to_df(company_message[0],company_message[4])
        df4['姓名'] = df4['姓名'].apply(dedup_name)
        # 对外投资
        df5 = col_is_vertical_to_df(company_message[0],company_message[5])
        # 变更记录
        df6 = col_is_vertical_to_df(company_message[0],company_message[6])

        # 检查目标xlsx是否存在,不存在则提前创建好
        if not os.path.exists(save_path):
            workbook = app.books.add()
            workbook.save(save_path)
            workbook.close()
            time.sleep(1)

            # 刚创建的时候,是空文件,重命名或新增对应工作表,进行第一次写入
            wb = app.books.open(save_path)
            wb.sheets[0].name = wb.sheets[0].name.replace('Sheet1','企业主页')
            wb.sheets.add('工商信息',after='企业主页')
            wb.sheets.add('股东信息',after='工商信息')
            wb.sheets.add('主要人员',after='股东信息')
            wb.sheets.add('对外投资',after='主要人员')
            wb.sheets.add('变更记录',after='对外投资')
            wb.save()
            wb.close()

        # 写数据进xlxs
        wb_write = app.books.open(save_path)
        regular_line(wb_write, '企业主页', df1)
        regular_line(wb_write, '工商信息', df2)
        Irregular_line(wb_write, '股东信息', df3)
        Irregular_line(wb_write, '主要人员', df4)
        Irregular_line(wb_write, '对外投资', df5)
        Irregular_line(wb_write, '变更记录', df6)
        wb_write.save()
        wb_write.close()
        time.sleep(1)

    app.quit()
except Exception as e:
    app.quit()
    print(e)

至此,就可以得到这两家公司的一些详细信息。

ps:

412状态码

如果遇到412状态码,则表示网页怀疑你的程序是爬虫机器人,弹出了验证页面,但是由于我这是静态网页的爬取,无法做到验证,所以就被迫中断了,这个时候你可以点击该网页进入验证,又或者换ip,header,cookie等信息继续爬取。

如果大家在 soup.find_all(‘a’,{‘class’: ‘title’})[0].get(‘href’)这里遇到点错误,可能是天眼查那边更新了网页代码,大家可以根据这个操作来更新代码。

①按F12进入开发者调试页面
在这里插入图片描述

②就点击“深圳市腾讯计算机系统有限公司”这个点击操作而言,右击,然后选择“检查”选项,然后就可以看到开发者调试页面那里也自动跳转到了相关的位置。
在这里插入图片描述

③我们可以看到,这是一个a标签,class为title的html代码,所以,如果报错,可根据这个操作更换。比如,class改为了company_title,那代码也可对应的改为:soup.find_all(‘a’,{‘class’: ‘company_title’})[0].get(‘href’)
在这里插入图片描述

最后,大家需要注意的是,爬取的时候需要适当的设置一下睡眠时间,不然会被检测到是爬虫机器人在操作,可能会弹出弹窗让你验证,这样会导致循环被中断。第二个就是某个时间段爬取量尽量不要太大,不然也是会被检测到的。

由于完整代码太多了,我不想粘贴到博客上,大家都是程序员,可以去我的github上自取:https://github.com/guiyang-yang/notes/blob/main/spider/get_company_message.ipynb

参考文献:https://docs.xlwings.org/en/stable/quickstart.html

注明:转载需注明本原地址链接,利用代码进行非法行为与本人无关。

创作不易啊。如果大家觉得这个笔记对你们有用的,麻烦帮忙点个赞加关注哦。

在这里插入图片描述

  • 94
    点赞
  • 133
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 107
    评论
### 回答1: 我可以提供一些有关爬取企业工商信息的建议:1. 使用 Python 的 Requests 库来请求企业工商信息的网页;2. 使用 Python 的 Beautiful Soup 库来解析网页;3. 使用 Python 的 Pandas 库来处理数据并提取你想要的信息;4. 使用 Python 的 Selenium 库来处理动态网页,以便获取更多的信息。 ### 回答2: Python 是一种功能强大的编程语言,它具有丰富的库和工具,可以用来爬取企业工商信息。 在爬取企业工商信息之前,我们首先需要确定要爬取的网站。可以选择一些官方的工商信息查询网站,例如国家企业信用信息公示系统、全国企业信用信息公示系统等。这些网站都提供了查询企业工商信息的功能。 接下来,我们需要使用 Python 的网络爬虫工具,例如 BeautifulSoup、Scrapy 等。这些工具可以帮助我们解析网页的结构和内容,从而提取我们需要的工商信息。 具体操作步骤如下: 1. 使用网络爬虫工具获取工商信息查询网站的 HTML 页面。 2. 利用工具解析 HTML 页面,定位到包含企业工商信息的标签,例如公司名称、注册资本、法定代表人等。 3. 提取所需的企业工商信息,并储存在合适的数据结构中,例如列表、字典等。 4. 可以选择将信息存储到数据库或者文件中,方便后续的分析和使用。 需要注意的是,爬取企业工商信息可能涉及到法律和隐私等问题,因此在爬取过程中需要遵守相关法律法规,确保信息安全和合法性。 使用 Python 爬取企业工商信息,可以方便快捷地获取大量的企业信息。而且由于 Python 语言简洁易学、库资源丰富,爬取企业工商信息的过程也相对简单。但是在实际操作中,可能会遇到验证码、反爬虫策略等问题,需要进一步的技术和方法来应对。
评论 107
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会点东西的普通人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值