当前位置:   article > 正文

python爬虫开发之“智联招聘”网页爬取_基于python的网络爬虫(智联招聘)开发与实现

基于python的网络爬虫(智联招聘)开发与实现

 

 

先贴上需求:

  1. 1. 输入起始页 和结束页 爬取智联招聘上 与python相关职业
  2.  2. 爬取的信息包括 就业岗位名称 薪资 地区 公司名称 需求{包括学历和经验}
  3.  3. 爬取的信息以字典形式保存到mongodb数据库中

    附上url  https://sou.zhaopin.com/?jl=681&kw=python&kt=3     点击 --->>>智联招聘

 

------------------------------------------分割线---------------------------------------------------------------

 

  1. 打开智联上述url 链接,发现会跳出以下画面:

能用requests 当然用requets的啦! 毕竟比较简洁嘛~  但很可惜,使用requests库是爬取不到信息滴 

我还真不信邪 从浏览器那儿头部全部复制下 带上 所有能用的都用了,结果。。 显然 这是一次失败的尝试。

(当然,有朋友通过抓包,可以找到 某个接口,通过对该接口使用 post 或 get 方法 同样也可以获取到信息,这也是一种方法。)

这里,我就使用究极方法  selenium + chromedriver 来实现。

2. 

https://sou.zhaopin.com/?p=1&jl=489&kw=python&kt=3&sf=0&st=0
观察url 可以发现  p 表示页码  kw表示关键字 jl等其它参数 不知道干啥滴 不过对我们爬取网站并没有影响

  3. 

    接下来就可以大展拳脚咯!!

    为了加快爬取速度 我采用了多线程的方式进行爬取, 使用  4个线程进行下载页面 3个线程进行解析页面并写入到Mongodb中。

    最重要的当然代码是如何实现的啦。

    代码中有详细的注释 有兴趣的可以看看~

  1. def main():
  2. startpage = eval(input('输入起始页码:'))
  3. endpage = eval(input('输入结束页码:'))
  4. # page 队列
  5. url_queue = Queue()
  6. # html 内容队列
  7. data_queue = Queue()
  8. spider = ZhiLianSpider(startpage, endpage, url_queue, data_queue)
  9. # 执行run方法返回一个url队列
  10. spider.run()
  11. # 创建生产者
  12. spider.create_producer()
  13. # 创建消费者
  14. spider.create_customer()
  15. # 阻塞.
  16. spider.wait_c()
  17. spider.wait_p()
  1. class ZhiLianSpider(object):
  2. # 定义类属性 生产者 和消费者
  3. pname = ['生产者1号', '生产者2号', '生产者3号', '生产者4号']
  4. cname = ['消费者1号', '消费者2号', '消费者3号']
  5. def __init__(self, start, end, urlqueue, dataqueue):
  6. self.start = start
  7. self.end = end
  8. self.url = r'https://sou.zhaopin.com/?p={}&jl=489&kw=python&kt=3&sf=0&st=0'
  9. self.urlqueue = urlqueue
  10. self.dataqueue = dataqueue
  11. # 创建一个生产者线程列表 用于阻塞等待
  12. self.p_threadlst = []
  13. # 创建一个消费者线程列表 用于阻塞等待
  14. self.c_threadlst = []
  15. # run 方法执行返回完整页面的url
  16. def run(self) -> None:
  17. for page in range(self.start, self.end + 1):
  18. self.urlqueue.put(self.url.format(page))
  19. def create_producer(self):
  20. '''
  21. 为了不使main函数中有太多冗余 将创建生产者和消费者放在这个类方法中
  22. :return:
  23. '''
  24. for name in self.pname:
  25. p = Producer(data_queue=self.dataqueue, url_queue=self.urlqueue, name=name)
  26. self.p_threadlst.append(p)
  27. # 启动线程
  28. p.start()
  29. def wait_p(self):
  30. for p in self.p_threadlst:
  31. p.join()
  32. def create_customer(self):
  33. for name in self.cname:
  34. c = Customer(self.dataqueue, name)
  35. self.c_threadlst.append(c)
  36. c.start()
  37. def wait_c(self):
  38. for c in self.c_threadlst:
  39. c.join()

 

生产者代码:

 

  1. class Producer(threading.Thread):
  2. '''
  3. 封装一下 chromedriver 无头浏览器参数
  4. '''
  5. options = Options()
  6. options.add_argument('--headless')
  7. options.add_argument('--disable-gpu')
  8. def __init__(self, data_queue, url_queue, name):
  9. super(Producer, self).__init__()
  10. self.data_queue = data_queue
  11. self.url_queue = url_queue
  12. self.name = name
  13. def run(self) -> None:
  14. '''
  15. 这里run方法主要实现两个方法 ① 下载页面 ② 将页面存到data_queue队列中
  16. :return: 这里的 ->None 表示返回的是空
  17. '''
  18. while not self.url_queue.empty():
  19. url = self.url_queue.get()
  20. # 下载页面
  21. print('我是{}---->>>>正在下载页面{}'.format(self.name, url.split('?')[1].split('&')[0]))
  22. self.download_html(url)
  23. print('我是{}---->>>>已完成下载页面{}'.format(self.name, url.split('?')[1].split('&')[0]))
  24. def download_html(self, url):
  25. # 创建一个浏览器对象
  26. browser = webdriver.Chrome('../chromedriver.exe', options=self.options)
  27. # 打开url
  28. browser.get(url)
  29. # 等待1秒
  30. time.sleep(1)
  31. # 处理弹出的按钮
  32. button = browser.find_element_by_css_selector('body > div.a-modal.risk-warning > div > div > button')
  33. # 点击按钮
  34. button.click()
  35. browser.implicitly_wait(3)
  36. # 等待js内容渲染
  37. time.sleep(2)
  38. # 将页面源码存入队列中
  39. self.data_queue.put(browser.page_source)
  40. # 最后最后一定要记得关闭浏览器! 因为这个函数是写在一个循环中的
  41. browser.quit()

   消费者:

  1. class Customer(threading.Thread):
  2. # 初始化mongodb参数
  3. # 连接服务器
  4. conn = MongoClient(host='localhost', port=27017)
  5. # 创建数据库
  6. db = conn.zhaopin
  7. # 创建集合
  8. collection = db.zhaopin_collection
  9. # 创建一个锁对象 当一个线程进行数据库的写入时 锁上 存储信息完毕后释放
  10. lock = threading.Lock()
  11. def __init__(self, data_queue, name):
  12. super(Customer, self).__init__()
  13. self.data_queue = data_queue
  14. self.name = name
  15. def run(self) -> None:
  16. while True:
  17. try:
  18. # 获取页面内容进行解析
  19. content = self.data_queue.get(True, 20)
  20. print('我是{},我正在解析...'.format(self.name))
  21. self.parse_content(content)
  22. except Exception:
  23. print('我是{},已经完成解析...'.format(self.name))
  24. break
  25. def parse_content(self, content):
  26. '''
  27. 观察网站源码发现 所有的招聘内容放在了一个 div容器中 取出这个容器 循环遍历即可
  28. <div id="listContent" class="contentpile__content">
  29. :param content:
  30. :return:
  31. '''
  32. # 创建一个列表用于存储字典信息
  33. info_list = []
  34. soup = BeautifulSoup(content, 'lxml')
  35. div_lst = soup.find('div', id='listContent')
  36. for item in div_lst:
  37. try:
  38. # 岗位名称
  39. jobname = item.find('span', class_='contentpile__content__wrapper__item__info__box__jobname__title')[
  40. 'title']
  41. # 工资
  42. saray = item.find('p', class_='contentpile__content__wrapper__item__info__box__job__saray').text
  43. # 地区
  44. area = item.find_all('li', class_='contentpile__content__wrapper__item__info__box__job__demand__item')[
  45. 0].text
  46. # 经验
  47. ex = item.find_all('li', class_='contentpile__content__wrapper__item__info__box__job__demand__item')[
  48. 1].text.strip(), \
  49. item.find_all('li', class_='contentpile__content__wrapper__item__info__box__job__demand__item')[
  50. 2].text.strip()
  51. # 公司名
  52. company_name = item.find('a',
  53. class_='contentpile__content__wrapper__item__info__box__cname__title company_title').text
  54. # 将信息存储为字典
  55. item_info = {
  56. '岗位名称': jobname,
  57. '工资': saray,
  58. '地区': area,
  59. '经验': ex,
  60. '公司名': company_name
  61. }
  62. info_list.append(item_info)
  63. except Exception:
  64. continue
  65. # 写入数据库
  66. self.lock.acquire()
  67. self.collection.insert_many(info_list)
  68. self.lock.release()

最后的最后 贴上我爬取的部分信息吧~

 

 

 

----------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

 

PS:优化一下代码,看看之前写的,啧啧,辣眼睛~

  1. # author:dayin
  2. # Date:2019/12/17 0017
  3. import time
  4. from selenium.webdriver.chrome.options import Options
  5. from selenium import webdriver
  6. from bs4 import BeautifulSoup
  7. from pymongo import MongoClient
  8. import threading
  9. from queue import Queue
  10. '''
  11. 需求: 输入起始页 和结束页 爬取智联招聘上python词条信息
  12. 爬取的信息包括 就业岗位名称 薪资 地区 公司名称 需求{包括学历和经验}
  13. 爬取的信息以字典形式保存到mongodb数据库中
  14. '''
  15. # 创建一个锁对象 当一个线程进行数据库的写入时 锁上 存储信息完毕后释放
  16. lock = threading.Lock()
  17. # 创建一个同步条件,用于任务结束的标志
  18. event = threading.Event()
  19. class ZhiLianSpider(object):
  20. # 定义类属性 生产者 和消费者
  21. pname = ['生产者1号', '生产者2号', '生产者3号', '生产者4号']
  22. cname = ['消费者1号', '消费者2号', '消费者3号']
  23. def __init__(self, start, end, urlqueue, dataqueue):
  24. self.start = start
  25. self.end = end
  26. self.url = r'https://sou.zhaopin.com/?p={}&jl=489&kw=python&kt=3&sf=0&st=0'
  27. self.urlqueue = urlqueue
  28. self.dataqueue = dataqueue
  29. # run 方法执行返回完整页面的url
  30. def run(self) -> None:
  31. for page in range(self.start, self.end + 1):
  32. self.urlqueue.put(self.url.format(page))
  33. def create_producer(self):
  34. '''
  35. 为了不使main函数中有太多冗余 将创建生产者和消费者放在这个类方法中
  36. :return:
  37. '''
  38. for name in self.pname:
  39. p = Producer(data_queue=self.dataqueue, url_queue=self.urlqueue, name=name)
  40. # 启动线程
  41. p.start()
  42. def create_customer(self):
  43. for name in self.cname:
  44. c = Customer(self.dataqueue, name)
  45. c.start()
  46. class Producer(threading.Thread):
  47. '''
  48. 封装一下 chromedriver 无头浏览器参数
  49. '''
  50. options = Options()
  51. options.add_argument('--headless')
  52. options.add_argument('--disable-gpu')
  53. def __init__(self, data_queue, url_queue, name):
  54. super(Producer, self).__init__()
  55. self.data_queue = data_queue
  56. self.url_queue = url_queue
  57. self.name = name
  58. def run(self) -> None:
  59. '''
  60. 这里run方法主要实现两个方法 ① 下载页面 ② 将页面存到data_queue队列中
  61. :return: 这里的 ->None 表示返回的是空
  62. '''
  63. while True:
  64. if self.url_queue.empty():
  65. event.set()
  66. break
  67. url = self.url_queue.get()
  68. # 下载页面
  69. print('我是{}---->>>>正在下载页面{}'.format(self.name, url.split('?')[1].split('&')[0]))
  70. self.download_html(url)
  71. print('我是{}---->>>>已完成下载页面{}'.format(self.name, url.split('?')[1].split('&')[0]))
  72. def download_html(self, url):
  73. # 创建一个浏览器对象
  74. browser = webdriver.Chrome('chromedriver.exe', options=self.options)
  75. # 打开url
  76. browser.get(url)
  77. # 等待1秒
  78. time.sleep(1)
  79. # 处理弹出的按钮
  80. button = browser.find_element_by_css_selector('body > div.a-modal.risk-warning > div > div > button')
  81. # 点击按钮
  82. button.click()
  83. browser.implicitly_wait(3)
  84. # 等待js内容渲染
  85. time.sleep(2)
  86. # 将页面源码存入队列中
  87. self.data_queue.put(browser.page_source)
  88. # 最后最后一定要记得关闭浏览器! 因为这个函数是写在一个循环中的
  89. browser.quit()
  90. class Customer(threading.Thread):
  91. # 初始化mongodb参数
  92. # 连接服务器
  93. conn = MongoClient(host='192.168.43.115', port=27017)
  94. # 创建数据库
  95. db = conn.zhaopin
  96. # 创建集合
  97. collection = db.zhaopin_collection
  98. def __init__(self, data_queue: Queue, name):
  99. super(Customer, self).__init__()
  100. self.data_queue = data_queue
  101. self.name = name
  102. def run(self) -> None:
  103. while True:
  104. # 获取页面内容进行解析
  105. if self.data_queue.empty() and event.is_set():
  106. print('任务完成...')
  107. break
  108. content = self.data_queue.get()
  109. print('我是{},我正在解析...'.format(self.name))
  110. self.parse_content(content)
  111. print('我是{},已经完成解析...'.format(self.name))
  112. def parse_content(self, content):
  113. '''
  114. 观察网站源码发现 所有的招聘内容放在了一个 div容器中 取出这个容器 循环遍历即可
  115. <div id="listContent" class="contentpile__content">
  116. :param content:
  117. :return:
  118. '''
  119. # 创建一个列表用于存储字典信息
  120. info_list = []
  121. soup = BeautifulSoup(content, 'lxml')
  122. div_lst = soup.find('div', id='listContent')
  123. try:
  124. for item in div_lst:
  125. try:
  126. # 岗位名称
  127. jobname = \
  128. item.find('span', class_='contentpile__content__wrapper__item__info__box__jobname__title')[
  129. 'title']
  130. # 工资
  131. saray = item.find('p', class_='contentpile__content__wrapper__item__info__box__job__saray').text
  132. # 地区
  133. area = \
  134. item.find_all('li', class_='contentpile__content__wrapper__item__info__box__job__demand__item')[
  135. 0].text
  136. # 经验
  137. ex = \
  138. item.find_all('li', class_='contentpile__content__wrapper__item__info__box__job__demand__item')[
  139. 1].text.strip(), \
  140. item.find_all('li', class_='contentpile__content__wrapper__item__info__box__job__demand__item')[
  141. 2].text.strip()
  142. # 公司名
  143. company_name = item.find('a',
  144. class_='contentpile__content__wrapper__item__info__box__cname__title company_title').text
  145. # 将信息存储为字典
  146. item_info = {
  147. '岗位名称': jobname,
  148. '工资': saray,
  149. '地区': area,
  150. '经验': ex,
  151. '公司名': company_name
  152. }
  153. info_list.append(item_info)
  154. except Exception:
  155. continue
  156. except Exception as e:
  157. print(e)
  158. # 写入数据库
  159. lock.acquire()
  160. self.collection.insert_many(info_list)
  161. lock.release()
  162. def main():
  163. startpage = eval(input('输入起始页码:'))
  164. endpage = eval(input('输入结束页码:'))
  165. # page 队列
  166. url_queue = Queue()
  167. # html 内容队列
  168. data_queue = Queue()
  169. spider = ZhiLianSpider(startpage, endpage, url_queue, data_queue)
  170. # 执行run方法返回一个url队列
  171. spider.run()
  172. # 创建生产者
  173. spider.create_producer()
  174. # 创建消费者
  175. spider.create_customer()
  176. if __name__ == '__main__':
  177. main()

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/421792
推荐阅读
相关标签
  

闽ICP备14008679号