zoukankan      html  css  js  c++  java
  • 用谷歌浏览器模拟打开天眼查网站并爬取需要的数据

    转载请注明地址: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=" 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=" 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
    高新企业
    电话:18768440137邮箱:暂无
    网址:http://www.atpanel.com
            # 地址:杭州市余杭区五常街道荆丰村'
            name = base.text.split('浏览')[0]
            tel = base.text.split('电话:')[1].split('邮箱:')[0]
            liulan = base.text.split('浏览')[1].split('
    ')[0]
            email = base.text.split('邮箱:')[1].split('
    ')[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
    高新企业
    电话:18768440137邮箱:暂无
    网址:http://www.atpanel.com
            # 地址:杭州市余杭区五常街道荆丰村'
            name = base.text.split('浏览')[0]
            tel = base.text.split('电话:')[1].split('邮箱:')[0]
            email = base.text.split('邮箱:')[1].split('
    ')[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()  # 释放数据库资源
  • 相关阅读:
    树形dp--P2014 [CTSC1997]选课
    背包变形--P1759 通天之潜水
    区间dp--P1880 [NOI1995]石子合并
    动态规划--P2758 编辑距离
    筛法--CF449C Jzzhu and Apples
    BZOJ3998: [TJOI2015]弦论(后缀自动机,Parent树)
    BZOJ3530: [Sdoi2014]数数(Trie图,数位Dp)
    BZOJ1444: [Jsoi2009]有趣的游戏(Trie图,矩乘)
    BZOJ1195: [HNOI2006]最短母串(Trie图,搜索)
    BZOJ3238: [Ahoi2013]差异(后缀数组)
  • 原文地址:https://www.cnblogs.com/bethansy/p/7683130.html
Copyright © 2011-2022 走看看