crawler爬虫实现

学习目标:
  1. 了解 crawler爬虫运行流程
  2. 了解 crawler爬虫模块实现

1. crawler功能

  1. 初始化driver
  2. 输入公司名称,并点击
  3. 判断是否需要验证
  4. 如果需要验证,获取验证图片并保存
  5. 获取打码坐标
  6. 点击验证图片
  7. 判断查询结果
  8. 选择第一条查询结果
  9. 获取主要信息
  10. 保存数据页面
  11. 向redis中发送信息
  12. 对失败情况进行保存,关闭driver,推送失败信息
  13. 组织抓取逻辑,成功关闭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命名,记录详细的日志信息
  • 对接第三方打码平台

小结

  1. 了解 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爬虫抓取数据相关推荐

  1. 【爬虫实战】国家企业公示网-crawler爬虫抓取数据

    crawler爬虫实现 1. crawler功能 2. crawler代码实现 3. 完成后的项目文件结构 4. 后续可以继续完善 学习目标 了解 crawler爬虫运行流程 了解 crawler爬虫 ...

  2. python爬取大众点评评论_python爬虫抓取数据 小试Python——爬虫抓取大众点评上的数据 - 电脑常识 - 服务器之家...

    python爬虫抓取数据 小试Python--爬虫抓取大众点评上的数据 发布时间:2017-04-07

  3. 基于Thinkphp5+phpQuery 网络爬虫抓取数据接口,统一输出接口数据api

    TP5_Splider 一个基于Thinkphp5+phpQuery 网络爬虫抓取数据接口 统一输出接口数据api.适合正在学习Vue,AngularJs框架学习 开发demo,需要接口并保证接口不跨 ...

  4. 如何使用Python爬虫抓取数据?

    Python爬虫应用十分广泛,无论是各类搜索引擎,还是日常数据采集,都需要爬虫的参与.其实爬虫的基本原理很简单,今天小编就教大家如何使用Python爬虫抓取数据,感兴趣的小伙伴赶紧看下去吧! 工具安装 ...

  5. 【入门-R爬虫抓取数据】文本挖掘之数据爬虫

    今天主要介绍一下,文本挖掘的数据获取方式,上一篇很多人在问数据如何获取,今天给大家介绍下数据获取的方式,主要利用爬虫抓取数据.基于,之前对python爬虫没接触过,尝试过用R爬虫,今天就来介绍下,如何 ...

  6. python爬虫抓取数据的步骤-Python爬虫抓取手机APP的传输数据

    大多数APP里面返回的是json格式数据,或者一堆加密过的数据 .这里以超级课程表APP为例,抓取超级课程表里用户发的话题. 1.抓取APP数据包 得到超级课程表登录的地址:http://120.55 ...

  7. 直播网站LiveTV Mining,爬虫抓取数据 python3+scrapy

    LiveTV Mining 介绍 项目实现爬虫.数据挖掘/分析等功能.目前主要是扫描直播站点收集数据,后续会开发相关数据分析模块. 架构采用前后端分离,通过RESTFul API通信.前端Vue+We ...

  8. Python爬虫抓取数据时怎么防止ip被封

    大数据公司在做数据分析的时候,对目标网站频繁访问很容易触发网站的反爬机制,因此如果想要突破限制只能使用动态ip频繁切换地址模拟真实客户访问网站才能起到防封效果.比如在做数据抓取的时候报错403等限制访 ...

  9. 使用selenium爬虫抓取数据

    文章目录 总体介绍 Selenium 安装 安装火狐浏览器插件Katalon Recorder 后台运行 简单教程 抓取网易房地产数据例子 参考链接 总体介绍 Selenium 简单入门教程 使用 S ...

最新文章

  1. XamlReader动态使用xaml
  2. 使用svnsync备份详解[转载+修改]
  3. 3.4 滑动窗口的卷积实现-深度学习第四课《卷积神经网络》-Stanford吴恩达教授
  4. nginx重新加载php,如何使用nginx启动、停止和重新加载
  5. MySQL: Starting MySQL….. ERROR! The server quit without updating PID file解决办法
  6. FODMAP饮食(持续更新中)
  7. 点击预览,有时可以打开,有时不可以
  8. 利用matlab提取中心线
  9. linux怎么才能算telnet成功_怎么表白才算成功呢
  10. newcondition java_Java并发Condition接口
  11. 大端机,小端机;截断与提升
  12. properties 配置回车_Dell?H730P?Raid1?配置方法
  13. 英国大学diploma(证书)期末考试挂科
  14. CenterNet :Objects as Points/CenterTrack:Tracking Objects as Points
  15. WIN10环境JAVA的JDK环境变量设置教程
  16. php的在线问卷调查_php 在线问卷调查程序一
  17. 单片机简易开发板怎么设计,我来告诉你
  18. 分布式数据库服务器时钟同步(NTP网络时钟同步)北斗卫星同步时钟起到关键性作用
  19. IntelliJ Idea 常用10款插件
  20. OC 主线程刷新UI

热门文章

  1. 推荐微信小程序常用的几个UI组件库
  2. 最新Python异步编程详解
  3. SAP那些事-职业篇-1-想做顾问如何入门
  4. sourcegraph/conc: Better structured concurrency for go
  5. 【 随笔 】 为什么要写技术文章
  6. 要做股市赢家:杨百万读书笔记
  7. 5、SRS4.0源代码分析之RTMP拉流处理
  8. 学术论文写作与发表经验分享
  9. Java筑基28-泛型
  10. linux怎么读取光盘文件,linux怎么读取光盘里的文件?