crawler爬虫抓取数据
crawler爬虫实现
学习目标:
- 了解 crawler爬虫运行流程
- 了解 crawler爬虫模块实现
1. crawler功能
- 初始化driver
- 输入公司名称,并点击
- 判断是否需要验证
- 如果需要验证,获取验证图片并保存
- 获取打码坐标
- 点击验证图片
- 判断查询结果
- 选择第一条查询结果
- 获取主要信息
- 保存数据页面
- 向redis中发送信息
- 对失败情况进行保存,关闭driver,推送失败信息
- 组织抓取逻辑,成功关闭driver
2. crawler代码实现
- 根据crawler的功能完成函数并组织运行逻辑
/gsxt/crawler.py
......class GsxtJSCrawler():"""爬虫"""def __init__(self, task_dict={}):self.crack_captcha_mode = task_dict.get('crack_captcha_mode', '0') # 打码策略 '0'手动破解;'1'调用打码平台self.token = task_dict.get('token', None) # tokenself.company_name = task_dict.get('company_name', None) # 公司名称self.proxy = None # 代理ip# self.proxy = 'http://182.88.185.38:8123'self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'}self.url = 'http://www.jsgsj.gov.cn:58888/province/' # 目前只有江苏 重庆等少数地区的接口还算稳定# self.url = 'http://www.gsxt.gov.cn/index.html'self.captcha_img = None # driver中的图片对象self.redis_key = '{}:{}'.format(GSXT_TASK_TOPIC, self.token)self.item = {} # 数据def init_driver(self):"""初始化driver"""if self.proxy:opation = webdriver.ChromeOptions()opation.add_argument('--proxy-server={}'.format(self.proxy))self.driver = webdriver.Chrome('/home/worker/Desktop/driver/chromedriver', chrome_options=opation)else:self.driver = webdriver.Chrome('/home/worker/Desktop/driver/chromedriver')# self.driver = webdriver.PhantomJS('/home/worker/Desktop/driver/phantomjs')self.driver.get(self.url)time.sleep(2)self.driver.set_window_size(800, 600)def send_company_name(self):"""输入公司名称,并点击"""self.driver.find_element_by_xpath('//*[@id="name"]').send_keys(self.company_name)time.sleep(1)self.driver.find_element_by_xpath('//a[@class="bt-chaxun"]').click()def check_captcha_img(self):"""判断是否需要验证"""i = 0while i < 3:try: # 手动显式等待验证码图片出现time.sleep(1)# 获取图片对象self.captcha_img = self.driver.find_element_by_xpath('//img[@class="geetest_item_img"]')return # self.captcha_img != Noneexcept:# 存在不需要验证的情况; 也存在滑动的情况# 对于滑动拼图就passif self.driver.current_url != self.url:return # self.captcha_img = Nonei += 1def get_captcha_img(self):"""获取验证图片并保存"""captcha_img_url = self.captcha_img.get_attribute('src')img_resp = requests.get(captcha_img_url, headers=self.headers)img = img_resp.contentprint(img)with open('./images/{}.jpg'.format(self.token), 'wb') as f:f.write(img)"""width:100%, height:112%使用PIL模块"""im = Image.open('./images/{}.jpg'.format(self.token))width, height = im.sizeim.thumbnail((width, height / 1.12))im.save('./images/{}.jpg'.format(self.token), 'JPEG')def get_captcha_offset(self):"""获取打码坐标"""# 手动打码if self.crack_captcha_mode == '0':i = 0while i < 180:captcha_offset = redis.hget(self.redis_key, 'captcha_params')if captcha_offset is not None:return captcha_offsettime.sleep(1)i += 1return None # 超时,没有获取打码坐标# 调用第三方打码elif self.crack_captcha_mode == '1':"""暂不实现"""return Noneelse:raise TypeError('仅支持webapi+redis+crawler组件模式的手动或者第三方打码方式')def click_captcha_offset(self, captcha_offset_str):"""点击验证坐标"""captcha_offset = []# captcha_offset_str = '247,202,142,150,'captcha_offset_list = captcha_offset_str.split(',')[:-1] # ['247', '202', '142', '150']for x in captcha_offset_list[::2]:y = captcha_offset_str.split(',')[:-1][captcha_offset_str.split(',')[:-1].index(x) + 1]captcha_offset.append((x, y))# captcha_offset = [('247', '202'), ('142', '150')]# captcha_offset = [(x, captcha_offset_str.split(',')[:-1][captcha_offset_str.split(',')[:-1].index(x)+1])# for x in captcha_offset_str.split(',')[:-1][::2]]"""点击破解"""for i in range(len(captcha_offset)):ActionChains(self.driver).move_to_element_with_offset(to_element=self.captcha_img,xoffset=int(captcha_offset[i][0]) - 0, # 保存的图片和页面上图片大小不一致!yoffset=int(captcha_offset[i][1]) - 0).perform()# 时间要随机time.sleep(1)time.sleep(random.random())ActionChains(self.driver).click().perform()input('注意!这里不光需要模拟真人操作的随机,而且从出现验证图片开始就检测鼠标点击和轨迹!哪怕使用打码平台也要加入无用的鼠标动作!')# 点击确认提交self.driver.find_element_by_xpath('//a[@class="geetest_commit"]').click()time.sleep(2)# 判断点击是否成功captcha_img = self.driver.find_elements_by_xpath('//img[@class="geetest_item_img"]')return False if captcha_img != [] else True # 如果还有验证图片就说明失败了def check_result(self):"""判断查询结果"""time.sleep(2)rets = self.driver.find_elements_by_xpath('//div[@class="listbox"]')return False if rets == [] else Truedef choice_first_result(self):"""选择第一条查询结果"""time.sleep(2)self.driver.find_element_by_xpath('//div[@class="listbox"]/a[1]').click()"""有时会跳出新的标签页,所以根据句柄强行切换到最后一个标签页"""self.driver.switch_to.window(self.driver.window_handles[-1])def get_baseinfo_item(self):"""获取主要信息"""i = 0while i<5: # 手动显式等待,等待页面加载完毕,以reg_no是否出现为标志reg_no = self.driver.find_elements_by_xpath('//*[@id="REG_NO"]')if reg_no != []:breaktime.sleep(3)i += 1# 统一社会信用代码/注册号REG_NOreg_no = self.driver.find_elements_by_xpath('//*[@id="REG_NO"]')if reg_no == []:return Falseself.item['reg_no'] = reg_no[0].text if id != [] else ''# 企业名称CORP_NAMEcorp_name = self.driver.find_elements_by_xpath('//*[@id="CORP_NAME"]')self.item['corp_name'] = corp_name[0].text if id != [] else ''# 类型ZJ_ECON_KINDzj_econ_kind = self.driver.find_elements_by_xpath('//*[@id="ZJ_ECON_KIND"]')self.item['zj_econ_kind'] = zj_econ_kind[0].text if id != [] else ''# 法定代表人OPER_MAN_NAMEoper_man_name = self.driver.find_elements_by_xpath('//*[@id="OPER_MAN_NAME"]')self.item['oper_man_name'] = oper_man_name[0].text if id != [] else ''# 注册资本REG_CAPIreg_cpi = self.driver.find_elements_by_xpath('//*[@id="REG_CAPI"]')self.item['reg_cpi'] = reg_cpi[0].text if id != [] else ''# 成立日期START_DATEstart_date = self.driver.find_elements_by_xpath('//*[@id="START_DATE"]')self.item['oper_man_name'] = start_date[0].text if id != [] else ''# 营业期限自FARE_TERM_STARTfare_term_start = self.driver.find_elements_by_xpath('//*[@id="FARE_TERM_START"]')self.item['fare_term_start'] = fare_term_start[0].text if id != [] else ''# 营业期限至FARE_TERM_ENDfare_term_end = self.driver.find_elements_by_xpath('//*[@id="FARE_TERM_END"]')self.item['fare_term_end'] = fare_term_end[0].text if id != [] else ''# 登记机关BELONG_ORGbelong_org = self.driver.find_elements_by_xpath('//*[@id="BELONG_ORG"]')self.item['belong_org'] = belong_org[0].text if id != [] else ''# 核准日期CHECK_DATEcheck_date = self.driver.find_elements_by_xpath('//*[@id="CHECK_DATE"]')self.item['check_date'] = check_date[0].text if id != [] else ''# 登记状态CORP_STATUScorp_status = self.driver.find_elements_by_xpath('//*[@id="CORP_STATUS"]')self.item['corp_status'] = corp_status[0].text if id != [] else ''# 住所ADDRaddr = self.driver.find_elements_by_xpath('//*[@id="ADDR"]')self.item['addr'] = addr[0].text if id != [] else ''# 经营范围FARE_SCOPEfare_scope = self.driver.find_elements_by_xpath('//*[@id="FARE_SCOPE"]')self.item['fare_scope'] = fare_scope[0].text if id != [] else ''return Truedef save_html(self):"""保存首页数据页面,后续可提取完整信息同样可以保存其他数据页"""file_name = './html/{}_base.html'.format(self.item['reg_no'])with open(file_name, 'w') as f:f.write(self.driver.page_source)def save_fail(self, msg):"""保存失败情况,关闭driver,推送失败信息"""# self.driver.save_screenshot('./error/{}.png'.format(self.token)) # 70版本的chrome不能调用截图功能print(msg)file_name = './error/{}_base.html'.format(self.token)with open(file_name, 'w') as f:f.write(self.driver.page_source)self.driver.quit() # 先保存失败,再关闭driver!self.send_msg_to_redis(msg=msg, status='failed')def send_msg_to_redis(self, msg, status):"""向redis中发送信息"""redis.hset(self.redis_key, 'status', status)redis.hset(self.redis_key, 'msg', msg)def _main(self):"""抓取逻辑"""if self.company_name is None:print('没有公司名称,查个毛线')returnif self.token is None:print('想单文件抓取自己写啊!')returntry: # 初始化driverself.init_driver()except:self.save_fail('初始化失败')returnself.send_msg_to_redis(msg='抓取进行中', status='crawling')try: # 输入公司名称点击self.send_company_name()except:input(11)self.save_fail('输入公司名称点击失败')returnself.check_captcha_img() # 检查是否需要验证if self.captcha_img is not None: # 需要验证的逻辑self.get_captcha_img() # 获取验证图片并保存captcha_offset_str = self.get_captcha_offset() # 获取打码结果print(captcha_offset_str)ret = self.click_captcha_offset(captcha_offset_str) # 点击验证坐标if not ret: # 验证点击失败self.save_fail('验证点击失败, 点对了也失败是因为同一ip访问次数过多, 请更换代理ip')returnif not self.check_result(): # 判断 没有结果就结束self.save_fail('查询失败')return"""仅对结果列表中第一个搞事情拿到所有html的page_source,并只返回主要信息提取数据的思路:提取一点就保存一点!"""self.choice_first_result() # 选择结果列表中第一个try:self.get_baseinfo_item() # 主要信息print(self.item)except:self.save_fail('提取数据失败')self.save_html() # 保存数据页面,后续可以提取完整信息# 先推数据,后推消息redis.hset(self.redis_key, 'data', self.item) # 向redis存数据self.send_msg_to_redis(msg='抓取成功', status='done')self.driver.quit() # 关闭浏览器# self.driver.service.process.pid # webdriver-server的piddef run(self):self._main()if __name__ == '__main__':server = CrawlerServer()server.crawl()
3. 完成后的项目文件结构
4. 后续可以继续完善
- 抓取更多的字段
- 保存更多的数据页面
- 以token命名,记录详细的日志信息
- 对接第三方打码平台
小结
了解 crawler爬虫运行流程
def run(self):
self._main()
if name == ‘main’:
server = CrawlerServer()
server.crawl()
### 3. 完成后的项目文件结构![在这里插入图片描述](https://img-blog.csdnimg.cn/09cc5e3b41464b719b2d411698c11c8e.png#pic_center)### 4. 后续可以继续完善- 抓取更多的字段
- 保存更多的数据页面
- 以token命名,记录详细的日志信息
- 对接第三方打码平台_________________## 小结
1. 了解 crawler爬虫运行流程
2. 了解 crawler爬虫模块实现
crawler爬虫抓取数据相关推荐
- 【爬虫实战】国家企业公示网-crawler爬虫抓取数据
crawler爬虫实现 1. crawler功能 2. crawler代码实现 3. 完成后的项目文件结构 4. 后续可以继续完善 学习目标 了解 crawler爬虫运行流程 了解 crawler爬虫 ...
- python爬取大众点评评论_python爬虫抓取数据 小试Python——爬虫抓取大众点评上的数据 - 电脑常识 - 服务器之家...
python爬虫抓取数据 小试Python--爬虫抓取大众点评上的数据 发布时间:2017-04-07
- 基于Thinkphp5+phpQuery 网络爬虫抓取数据接口,统一输出接口数据api
TP5_Splider 一个基于Thinkphp5+phpQuery 网络爬虫抓取数据接口 统一输出接口数据api.适合正在学习Vue,AngularJs框架学习 开发demo,需要接口并保证接口不跨 ...
- 如何使用Python爬虫抓取数据?
Python爬虫应用十分广泛,无论是各类搜索引擎,还是日常数据采集,都需要爬虫的参与.其实爬虫的基本原理很简单,今天小编就教大家如何使用Python爬虫抓取数据,感兴趣的小伙伴赶紧看下去吧! 工具安装 ...
- 【入门-R爬虫抓取数据】文本挖掘之数据爬虫
今天主要介绍一下,文本挖掘的数据获取方式,上一篇很多人在问数据如何获取,今天给大家介绍下数据获取的方式,主要利用爬虫抓取数据.基于,之前对python爬虫没接触过,尝试过用R爬虫,今天就来介绍下,如何 ...
- python爬虫抓取数据的步骤-Python爬虫抓取手机APP的传输数据
大多数APP里面返回的是json格式数据,或者一堆加密过的数据 .这里以超级课程表APP为例,抓取超级课程表里用户发的话题. 1.抓取APP数据包 得到超级课程表登录的地址:http://120.55 ...
- 直播网站LiveTV Mining,爬虫抓取数据 python3+scrapy
LiveTV Mining 介绍 项目实现爬虫.数据挖掘/分析等功能.目前主要是扫描直播站点收集数据,后续会开发相关数据分析模块. 架构采用前后端分离,通过RESTFul API通信.前端Vue+We ...
- Python爬虫抓取数据时怎么防止ip被封
大数据公司在做数据分析的时候,对目标网站频繁访问很容易触发网站的反爬机制,因此如果想要突破限制只能使用动态ip频繁切换地址模拟真实客户访问网站才能起到防封效果.比如在做数据抓取的时候报错403等限制访 ...
- 使用selenium爬虫抓取数据
文章目录 总体介绍 Selenium 安装 安装火狐浏览器插件Katalon Recorder 后台运行 简单教程 抓取网易房地产数据例子 参考链接 总体介绍 Selenium 简单入门教程 使用 S ...
最新文章
- XamlReader动态使用xaml
- 使用svnsync备份详解[转载+修改]
- 3.4 滑动窗口的卷积实现-深度学习第四课《卷积神经网络》-Stanford吴恩达教授
- nginx重新加载php,如何使用nginx启动、停止和重新加载
- MySQL: Starting MySQL….. ERROR! The server quit without updating PID file解决办法
- FODMAP饮食(持续更新中)
- 点击预览,有时可以打开,有时不可以
- 利用matlab提取中心线
- linux怎么才能算telnet成功_怎么表白才算成功呢
- newcondition java_Java并发Condition接口
- 大端机,小端机;截断与提升
- properties 配置回车_Dell?H730P?Raid1?配置方法
- 英国大学diploma(证书)期末考试挂科
- CenterNet :Objects as Points/CenterTrack:Tracking Objects as Points
- WIN10环境JAVA的JDK环境变量设置教程
- php的在线问卷调查_php 在线问卷调查程序一
- 单片机简易开发板怎么设计,我来告诉你
- 分布式数据库服务器时钟同步(NTP网络时钟同步)北斗卫星同步时钟起到关键性作用
- IntelliJ Idea 常用10款插件
- OC 主线程刷新UI