转载请注明地址: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">详情></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() # 释放数据库资源