用谷歌浏览器模拟打开天眼查网站并爬取需要的数据

时间:2021-08-20 06:25:12

转载请注明地址:http://www.cnblogs.com/bethansy/p/7683130.html

安装软件,部署各种环境

   (1)安装软件

       安装python3.6 和pycharm2017,都在官网上下载即可。注意安装python3.6时注意勾选添加环境变量,安装pycharm后,打开软件会让你激活,按照下面的步骤操作即可

第一步:一路默认到这个输入注册码的页面
第二步:选择中间的license输入http://idea.lanyus.com这个网址
第三步:浏览器打开http://idea.lanyus.com后,点击获得注册码,复制注册码
第四步:将复制的注册码粘贴到里activation对应的框里去
第五步:点击ok完成安装

(2)安装第三方库

    由于需要用浏览器模拟,需要用到selenium、pymysql等第三方库。我一般喜欢使用pip来进行安装,如何用pip进行第三方库的安装可以看我以前写的博客

http://www.cnblogs.com/bethansy/p/7029023.html

(3)由于需要python来操作chrome,所以还需要下载一个谷歌浏览器放在python本地目录下

第一步:首先保证本地电脑带有chrome

第二步:根据自己chrome版本下载相应的谷歌驱动,下载地址 http://blog.csdn.net/huilan_same/article/details/51896672

第三步:将下载好的驱动放在python安装目录下,如图所示

 用谷歌浏览器模拟打开天眼查网站并爬取需要的数据

二、开始爬虫

 1.建立浏览器,打开指定路径的页面,输入用户名,密码,点击登陆

       driver = webdriver.Chrome()
        driver.get(url)

        # 模拟登陆
        driver.find_element_by_xpath(
            ".//*[@id='web-content']/div/div/div/div[2]/div/div[2]/div[2]/div[2]/div[2]/input"). \
            send_keys(username)
        driver.find_element_by_xpath(
            ".//*[@id='web-content']/div/div/div/div[2]/div/div[2]/div[2]/div[2]/div[3]/input"). \
            send_keys(password)
        driver.find_element_by_xpath(
            ".//*[@id='web-content']/div/div/div/div[2]/div/div[2]/div[2]/div[2]/div[5]").click()
        time.sleep(3)
        driver.refresh()

 注意其中的time.sleep(3)是让浏览器休眠3秒,模拟得像个人的操作,不然机器控制速度太快,会被目标网站识别出来

 2.输入搜索内容 ,点击查找按钮,跳转到第二张页面,选择相关度最高的第一条内容进行点击,跳转到第三张页面,此时网页上打开了两个窗口

 driver.find_element_by_xpath(".//*[@id='home-main-search']").send_keys(self.word)  # 输入搜索内容
 driver.find_element_by_xpath(".//*[@class='input-group-addon search_button']").click()  # 点击搜索

用谷歌浏览器模拟打开天眼查网站并爬取需要的数据用谷歌浏览器模拟打开天眼查网站并爬取需要的数据用谷歌浏览器模拟打开天眼查网站并爬取需要的数据

 3.转换句柄

    此时drive指针还在搜索框页面,但是我们要抓取的是弹开的第二张网页上的内容,于是需要driver的指针移动到第二张网页上。 

        now_handle = driver.current_window_handle
        all_handles = driver.window_handles for handle in all_handles: if handle != now_handle: # 输出待选择的窗口句柄 print(handle) driver.switch_to.window(handle)

  4.抓取网页数据

(1)抓取网站基本信息

    页面展示如下,除了获取基本信息以外,还要获取每个表格的内容再对应放在不同的数据表中

用谷歌浏览器模拟打开天眼查网站并爬取需要的数据用谷歌浏览器模拟打开天眼查网站并爬取需要的数据

 

<div class="company_header_width ie9Style"><div><span class="f18 in-block vertival-middle sec-c2" style="font-weight: 600">淘宝(中国)软件有限公司</span><span class="describeIcon point sec-c3 pl5" style="font-weight: 100;display: inline-block"><span class="tic tic-circle-question-o"></span><span class="discribeBox block"><span class="triangle-with-shadow"></span><span class="describeContent block f14" style="z-index: 100;line-height: 24px;"><span class="text-left sec-c2 block">企业名称:公司的名称和住所是公司登记的主要事项,也是设立公司的组织条件。<br>公司名称的意义主要有...<a class="float-right" href="/describe/name">详情&gt;</a></span><span class="position-abs text-center sec-c4 pl5 block" style="bottom: 5px;">* 以上数据由天眼查合作伙伴<span class="sec-cyel">北大法宝</span>提供</span></span></span></span><!--曾用名--><span class="pl10 sec-c3 f12">浏览<span class="pl4">43766</span></span><p class="f14 mt10" style="line-height: 1.42857143;"><span class="border-radio2 f12 pl8 pr8 pt3 pb3 company-tag mr5">高新企业</span><!--公司性质--><!--1,公司,2香港,3社会组织,4律所--><!--上市信息--></p><!--联系方式等--><div class="f14 sec-c2 mt10" style="line-height: 26px;"><div class="in-block vertical-top overflow-width mr20" style="width: 220px;"><span class="sec-c3">电话:</span><span>18768440137</span></div><div class="in-block vertical-top"><span class="in-block vertical-top sec-c3">邮箱:</span><span class="in-block vertical-top overflow-width emailWidth">暂无</span></div></div><div class="f14 sec-c2" style="line-height: 26px;"><div class="in-block vertical-top overflow-width mr20" style="width: 220px;"><span class="sec-c3">网址:</span><a target="_blank" href="http://www.atpanel.com" nofollow="" class="c9">http://www.atpanel.com</a></div><div class="in-block vertical-top"><span class="in-block vertical-top sec-c3">地址:</span><span class="in-block overflow-width vertical-top emailWidth" title="杭州市余杭区五常街道荆丰村">杭州市余杭区五常街道荆丰村</span></div></div></div><div class="sec-c2 over-hide" style="line-height: 24px;"><span><span class="sec-c3">简介:</span>淘宝(中国)软件有限公司成立于2004年12月07日,主要经营范围为研究、开发计算机软、硬...</span><script type="text/html" id="company_base_info_detail">
                  淘宝(中国)软件有限公司成立于2004年12月07日,主要经营范围为研究、开发计算机软、硬件,网络技术产品,多媒体产品等。
                </script><span class="c9 point hover_underline" onclick="companyDetail()">详情</span></div></div>

 

(1)获取公司的基本信息,例如名字,地址,邮编,简介等

 def baseInfo(self):
        base = self.driver.find_element_by_xpath("//div[@class='company_header_width ie9Style']/div")
        # base '淘宝(中国)软件有限公司浏览40770\n高新企业\n电话:18768440137邮箱:暂无\n网址:http://www.atpanel.com
        # 地址:杭州市余杭区五常街道荆丰村'
        name = base.text.split('浏览')[0]
        tel = base.text.split('电话:')[1].split('邮箱:')[0]
        liulan = base.text.split('浏览')[1].split('\n')[0]
        email = base.text.split('邮箱:')[1].split('\n')[0]
        web = base.text.split('网址:')[1].split('地址')[0]
        address = base.text.split('地址:')[1]
        abstract = self.driver.find_element_by_xpath("//div[@class='sec-c2 over-hide']//script")
        # 获取隐藏内容
        abstract = self.driver.execute_script("return arguments[0].textContent", abstract).strip()
        tabs = self.driver.find_elements_by_tag_name('table')
        rows = tabs[1].find_elements_by_tag_name('tr')
        cols = rows[0].find_elements_by_tag_name('td' and 'th')
        # 工商主策号
        reg_code = rows[0].find_elements_by_tag_name('td')[1].text
        # 注册地址
        reg_address = rows[5].find_elements_by_tag_name('td')[1].text
        # 英文名称
        english_name = rows[5].find_elements_by_tag_name('td')[1].text
        # 经营范围
        ent_range = rows[6].find_elements_by_tag_name('td')[1].text
        # 统一信用代码
        creditcode = rows[1].find_elements_by_tag_name('td')[1].text
        # 纳税人识别号
        tax_code = rows[2].find_elements_by_tag_name('td')[1].text
        # 营业期限
        deadline = rows[3].find_elements_by_tag_name('td')[1].text
        # 企业类型
        ent_type = rows[1].find_elements_by_tag_name('td')[3].text
        idd = str(uuid.uuid1())
        idd.replace('-', '')

        BasedInfo = (idd, name, tel, email, web, address, abstract, reg_code, reg_address, english_name, ent_range,
                     creditcode, tax_code, deadline, ent_type)

        self.base(BasedInfo)

    def base(self, baseing):
        conn = pymysql.connect(host='localhost', user='root', passwd='123', db='tianyan', port=3306, charset='utf8')
        cur = conn.cursor()  # 获取一个游标
        sql = "INSERT INTO ent_basic (ent_uid, ent_name, entPhone, entEmail, ent_url, ent_address, ent_desc," \
              " ent_reg_no,ent_reg_address, ent_english_name, ent_range, credit_code, tax_person_code, entDeadline, " \
              "ent_type) VALUES ( '%s', '%s', '%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s' )"
        cur.execute(sql % baseing)
        conn.commit()
        cur.close()  # 关闭游标
        conn.close()  # 释放数据库资源

(2)获取网页表格信息

    查看源码发现所有的表格都一个共同的特征,所以通过查找所有id

用谷歌浏览器模拟打开天眼查网站并爬取需要的数据

tables = driver.find_elements_by_xpath("//div[contains(@id,'_container_')]")

 2.1 获取表格以后继续抓取需要的内容

 用谷歌浏览器模拟打开天眼查网站并爬取需要的数据

   def jiexitable(self, x):
        rows = x.find_elements_by_tag_name('tr')
        # 第二个表格是th 有没有什么方法可以同时查找td或者th!!!!! and 和 or
        cols = rows[0].find_elements_by_tag_name('td' or 'th')
        result = [[0 for col in range(len(cols))] for row in range(len(rows))]
        # 创建一个二维列表
        for i in range(len(rows)):
            for j in range(len(cols)):
                result[i][j] = rows[i].find_elements_by_tag_name('td')[j].text
        return result

 2.2 判断是否有翻页标记

    表格下有翻页标记的,一般web元素中都有li标签,去获取li标签,如果有的话就进行翻页操作,继续获取第二页以及后面几页的内容

用谷歌浏览器模拟打开天眼查网站并爬取需要的数据

 

    def trytable(self, x):
        # 是否需要去掉get_attribute ,得到的是table的名字 ,若没得表格到flag则为0
        try:
            x.find_element_by_tag_name('table').get_attribute('class')
            flag = 1
        except Exception:
            flag = 0
            print("这不是表格")
        return flag

    def tryonclick(self, x):
        # 测试是否有翻页
        try:
            # 找到有翻页标记
            x.find_element_by_tag_name('ul')
            onclickflag = 1
        except Exception:
            print("没有翻页")
            onclickflag = 0
        return onclickflag

 2.3 点击翻页按钮 

 def jiexionclick(self, x, result):
        PageCount = x.find_element_by_xpath("//div[@class='total']").text
        PageCount = re.sub("\D", "", PageCount)  # 使用正则表达式取字符串中的数字 ;\D表示非数字的意思
        for i in range(PageCount - 1):
            button = x.find_element_by_xpath(".//li[@class='pagination-next  ']/a")
            button.click()
            table = x.find_element_by_tag_name('tbody')
            turnpagetable = self.jiexitable(table)
            result.append(turnpagetable)
        return result

    但是经常onclick按钮会出错,并提示这个元素没有click属性,所以以后抓取大型网站的数据最好还是用scrapy模块比较好。后来网友提醒用Firefox浏览器就不会存在这个问题了。

2.4 多条语句插入数据库

解析表格,将表格的内容一起插入数据库,在表格框架的基础上增加两列。分别是数据表的id和外键盘ent_uid ,在执行插入语句即可大功告成

    def jiexitable(self, x, id):
        rows = x.find_elements_by_tag_name('tr')
        # 第二个表格是th 有没有什么方法可以同时查找td或者th!!!!! and 和 or
        cols = rows[0].find_elements_by_tag_name('td' or 'th')
        result = [[0 for col in range(len(cols)+2)] for row in range(len(rows))]
        # 创建一个二维列表
        for i in range(len(rows)):
            result[i][0] = id
            idd = str(uuid.uuid1())
            idd = idd.replace('-', '')
            result[i][1] = idd
            for j in range(len(cols)):
                result[i][j+2] = rows[i].find_elements_by_tag_name('td')[j].text
        data = list(map(tuple, result)) # 将列表变成元组格式才能被插入数据库中
        return data
conn = pymysql.connect(host='10.2.1.190', user='root', passwd='123', db='tianyan', port=3306, charset='utf8')
    cur = conn.cursor()  # 获取一个游标
    sql = "INSERT INTO ent_competor ( idd,product, region, turn, industry, service, creat_time," \
          " estimate_value) VALUES ( '%s', '%s', '%s','%s','%s','%s','%s','%s' )"

    cur.executemany(sql, table)
    conn.commit()

 

5、完整代码

#!/usr/bin/python
# -*- coding: UTF-8 -*-
#  天眼查网站

import re
from selenium import webdriver
import time
import uuid
import conn_mysql

class mainAll(object):

    def __init__(self):
        self.url = 'https://www.tianyancha.com/login'
        self.username = '15160773967'
        self.password = 'yy171827'
        self.word = '淘宝'
        self.driver = self.login()
        self.scrapy(self.driver)
        print("ok,the work is done!")

    def login(self):
        driver = webdriver.Chrome()
        driver.get(self.url)

        # 模拟登陆
        driver.find_element_by_xpath(
            ".//*[@id='web-content']/div/div/div/div[2]/div/div[2]/div[2]/div[2]/div[2]/input"). \
            send_keys(self.username)
        driver.find_element_by_xpath(
            ".//*[@id='web-content']/div/div/div/div[2]/div/div[2]/div[2]/div[2]/div[3]/input"). \
            send_keys(self.password)
        driver.find_element_by_xpath(
            ".//*[@id='web-content']/div/div/div/div[2]/div/div[2]/div[2]/div[2]/div[5]").click()
        time.sleep(3)
        driver.refresh()
        # driver.get('https://www.tianyancha.com/company/28723141')

        # 模拟登陆完成,输入搜索内容
        driver.find_element_by_xpath(".//*[@id='home-main-search']").send_keys(self.word)  # 输入搜索内容
        driver.find_element_by_xpath(".//*[@class='input-group-addon search_button']").click()  # 点击搜索
        driver.implicitly_wait(10)

        # 选择相关度最高的搜索结果 第一条搜索框,然后再
        tag = driver.find_elements_by_xpath("//div[@class='search_right_item']")
        tag[0].find_element_by_tag_name('a').click()
        driver.implicitly_wait(5)

        # 转化句柄
        now_handle = driver.current_window_handle
        all_handles = driver.window_handles
        for handle in all_handles:
            if handle != now_handle:
                # 输出待选择的窗口句柄
                print(handle)
                driver.switch_to.window(handle)
        return driver

    #  获取所有表格和表单
    def scrapy(self, driver):
        tables = driver.find_elements_by_xpath("//div[contains(@id,'_container_')]")

        # 获取每个表格的名字
        c = '_container_'
        name = [0] * (len(tables) - 2)
        # 生成一个独一无二的十六位参数作为公司标记,一个公司对应一个,需要插入多个数据表
        id = 'word'
        table_list = [0] * (len(tables) - 2)
        for x in range(0, len(tables) - 2):
            name[x] = tables[x].get_attribute('id')
            name[x] = name[x].replace(c, '')  # 可以用这个名称去匹配数据库
            # 判断是表格还是表单
            num = tables[x].find_elements_by_tag_name('table')

            # 基本信息表table有两个
            if len(num) > 1:
                result = self.baseInfo(tables[x], id)
                self.inser_sql(name[x], result)

            #  单纯的表格
            elif len(num) == 1:
                table = tables[x].find_element_by_tag_name('tbody')
                table_list = self.jiexitable(table, id)
                onclickflag = self.tryonclick(tables[x])

                # 判断此表格是否有翻页功能
                if onclickflag == 1:
                    table_list = self.jiexionclick(tables[x], table_list)

                print(table_list)
            # 表单样式
            elif len(num) == 0:
                continue
            table_list + id
            self.inser_sql(name[x], table_list)

        print(name)
        return name

    def trytable(self, x):
        # 是否需要去掉get_attribute ,得到的是table的名字 ,若没得表格到flag则为0
        try:
            x.find_element_by_tag_name('table').get_attribute('class')
            flag = 1
        except Exception:
            flag = 0
            print("这不是表格")
        return flag

    def tryonclick(self, x):
        # 测试是否有翻页
        try:
            # 找到有翻页标记
            x.find_element_by_tag_name('ul')
            onclickflag = 1
        except Exception:
            print("没有翻页")
            onclickflag = 0
        return onclickflag

    def jiexionclick(self, x, result):
        PageCount = x.find_element_by_xpath("//div[@class='total']").text
        PageCount = re.sub("\D", "", PageCount)  # 使用正则表达式取字符串中的数字 ;\D表示非数字的意思
        for i in range(PageCount - 1):
            button = x.find_element_by_xpath(".//li[@class='pagination-next  ']/a")
            button.click()
            table = x.find_element_by_tag_name('tbody')
            turnpagetable = self.jiexitable(table)
            result.append(turnpagetable)
        return result

    def jiexitable(self, x, id):
        rows = x.find_elements_by_tag_name('tr')
        # 第二个表格是th 有没有什么方法可以同时查找td或者th!!!!! and 和 or
        cols = rows[0].find_elements_by_tag_name('td' or 'th')
        result = [[0 for col in range(len(cols)+2)] for row in range(len(rows))]
        # 创建一个二维列表
        for i in range(len(rows)):
            result[i][0] = id
            idd = str(uuid.uuid1())
            idd = idd.replace('-', '')
            result[i][1] = idd
            for j in range(len(cols)):
                result[i][j+2] = rows[i].find_elements_by_tag_name('td')[j].text
        data = list(map(tuple, result)) # 将列表变成元组格式才能被插入数据库中
        return data

    def baseInfo(self, idd):
        base = self.driver.find_element_by_xpath("//div[@class='company_header_width ie9Style']/div")
        # base '淘宝(中国)软件有限公司浏览40770\n高新企业\n电话:18768440137邮箱:暂无\n网址:http://www.atpanel.com
        # 地址:杭州市余杭区五常街道荆丰村'
        name = base.text.split('浏览')[0]
        tel = base.text.split('电话:')[1].split('邮箱:')[0]
        email = base.text.split('邮箱:')[1].split('\n')[0]
        web = base.text.split('网址:')[1].split('地址')[0]
        address = base.text.split('地址:')[1]
        abstract = self.driver.find_element_by_xpath("//div[@class='sec-c2 over-hide']//script")
        # 获取隐藏内容
        abstract = self.driver.execute_script("return arguments[0].textContent", abstract).strip()
        tabs = self.driver.find_elements_by_tag_name('table')
        rows = tabs[1].find_elements_by_tag_name('tr')
        cols = rows[0].find_elements_by_tag_name('td' and 'th')
        # 工商注册号
        reg_code = rows[0].find_elements_by_tag_name('td')[1].text
        # 注册地址
        reg_address = rows[5].find_elements_by_tag_name('td')[1].text
        # 英文名称
        english_name = rows[5].find_elements_by_tag_name('td')[1].text
        # 经营范围
        ent_range = rows[6].find_elements_by_tag_name('td')[1].text
        # 统一信用代码
        creditcode = rows[1].find_elements_by_tag_name('td')[1].text
        # 纳税人识别号
        tax_code = rows[2].find_elements_by_tag_name('td')[1].text
        # 营业期限
        deadline = rows[3].find_elements_by_tag_name('td')[1].text
        # 企业类型
        ent_type = rows[1].find_elements_by_tag_name('td')[3].text

        baseInfo = (idd, name, tel, email, web, address, abstract, reg_code, reg_address, english_name, ent_range,
                    creditcode, tax_code, deadline, ent_type)

        return baseInfo

    def inser_sql(self, title, table):

        if title == 'baseInfo':
            conn_mysql.baseInfo(table)
        elif title == 'staff':
            conn_mysql.staff(table)
        elif title == 'holder':
            conn_mysql.holder(table)
        elif title == 'invest':
            conn_mysql.invest(table)
        elif title == 'jingpin':
            conn_mysql.jingpin(table)

if __name__ == '__main__':
    mainAll()

 

这个脚本还有调用另一个叫conn_mysql.py的模块

    conn_mysql模块的内容如下所示:

import pymysql


def staff(table):
    # 名称 职位 公司名称  entuid
    conn = pymysql.connect(host='10.2.1.190', user='root', passwd='123', db='tianyan', port=3306, charset='utf8')
    cur = conn.cursor()  # 获取一个游标
    sql = "INSERT INTO person (ent_uid, name, role,entName,entUid) VALUES ( '%s', '%s')"
    cur.execute(sql % table)
    conn.commit()
    cur.close()  # 关闭游标
    conn.close()  # 释放数据库资源


def holder(table):
    # 并没有插入股东总量,出资从总额,认缴出资币种,直接从表格上爬取内容入库而已
    #  id ent_uid 股东名称 出资比例 认缴出资额
    conn = pymysql.connect(host='10.2.1.190', user='root', passwd='123', db='tianyan', port=3306, charset='utf8')
    cur = conn.cursor()  # 获取一个游标
    sql = "INSERT INTO share_holder (id, ent_uid, shaName, fundeRatio, subConam)" \
          " VALUES ( '%s', '%s', '%s','%s','%s')"
    cur.execute(sql % table)
    conn.commit()
    cur.close()  # 关闭游标
    conn.close()  # 释放数据库资源


def invest(table):
    #  id ,ent_uid, 投资设立企业名称,法人,建立日期(姑且当做注册日期),出资金额,企业状态
    conn = pymysql.connect(host='10.2.1.190', user='root', passwd='123', db='tianyan', port=3306, charset='utf8')
    cur = conn.cursor()  # 获取一个游标
    sql = "INSERT INTO outinvest (id, ent_uid, name, legalPerson, buildDate, regMoney,entStatus)" \
          " VALUES ( '%s', '%s', '%s','%s','%s','%s','%s' )"
    cur.execute(sql % table)
    conn.commit()
    cur.close()  # 关闭游标
    conn.close()


def base(table):

    conn = pymysql.connect(host='10.2.1.190', user='root', passwd='123', db='tianyan', port=3306, charset='utf8')
    cur = conn.cursor()  # 获取一个游标
    sql = "INSERT INTO ent_basic (ent_uid, ent_name, entPhone, entEmail, ent_url, ent_address, ent_desc," \
          " ent_reg_no,ent_reg_address, ent_english_name, ent_range, credit_code, tax_person_code, entDeadline, " \
          "ent_type) VALUES ( '%s', '%s', '%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s' )"
    cur.execute(sql % table)
    conn.commit()
    cur.close()  # 关闭游标
    conn.close()  # 释放数据库资源


def jingpin(table):
    # 注意数据表设计的时候id是整数还是字符串,其他字段的字符串类型需要选择utf8
    conn = pymysql.connect(host='10.2.1.190', user='root', passwd='123', db='tianyan', port=3306, charset='utf8')
    cur = conn.cursor()  # 获取一个游标
    sql = "INSERT INTO ent_competor ( idd,product, region, turn, industry, service, creat_time," \
          " estimate_value) VALUES ( '%s', '%s', '%s','%s','%s','%s','%s','%s' )"

    cur.executemany(sql, table)
    conn.commit()
    cur.close()  # 关闭游标
    conn.close()  # 释放数据库资源