赞
踩
先贴上需求:
- 1. 输入起始页 和结束页 爬取智联招聘上 与python相关职业
- 2. 爬取的信息包括 就业岗位名称 薪资 地区 公司名称 需求{包括学历和经验}
- 3. 爬取的信息以字典形式保存到mongodb数据库中
附上url https://sou.zhaopin.com/?jl=681&kw=python&kt=3 点击 --->>>智联招聘
------------------------------------------分割线---------------------------------------------------------------
能用requests 当然用requets的啦! 毕竟比较简洁嘛~ 但很可惜,使用requests库是爬取不到信息滴
我还真不信邪 从浏览器那儿头部全部复制下 带上 所有能用的都用了,结果。。 显然 这是一次失败的尝试。
(当然,有朋友通过抓包,可以找到 某个接口,通过对该接口使用 post 或 get 方法 同样也可以获取到信息,这也是一种方法。)
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中。
最重要的当然代码是如何实现的啦。
代码中有详细的注释 有兴趣的可以看看~
- def main():
- startpage = eval(input('输入起始页码:'))
- endpage = eval(input('输入结束页码:'))
- # page 队列
- url_queue = Queue()
- # html 内容队列
- data_queue = Queue()
- spider = ZhiLianSpider(startpage, endpage, url_queue, data_queue)
- # 执行run方法返回一个url队列
- spider.run()
- # 创建生产者
- spider.create_producer()
- # 创建消费者
- spider.create_customer()
- # 阻塞.
- spider.wait_c()
- spider.wait_p()
- class ZhiLianSpider(object):
- # 定义类属性 生产者 和消费者
- pname = ['生产者1号', '生产者2号', '生产者3号', '生产者4号']
- cname = ['消费者1号', '消费者2号', '消费者3号']
-
- def __init__(self, start, end, urlqueue, dataqueue):
- self.start = start
- self.end = end
- self.url = r'https://sou.zhaopin.com/?p={}&jl=489&kw=python&kt=3&sf=0&st=0'
- self.urlqueue = urlqueue
- self.dataqueue = dataqueue
- # 创建一个生产者线程列表 用于阻塞等待
- self.p_threadlst = []
- # 创建一个消费者线程列表 用于阻塞等待
- self.c_threadlst = []
-
- # run 方法执行返回完整页面的url
- def run(self) -> None:
- for page in range(self.start, self.end + 1):
- self.urlqueue.put(self.url.format(page))
-
- def create_producer(self):
- '''
- 为了不使main函数中有太多冗余 将创建生产者和消费者放在这个类方法中
- :return:
- '''
- for name in self.pname:
- p = Producer(data_queue=self.dataqueue, url_queue=self.urlqueue, name=name)
- self.p_threadlst.append(p)
- # 启动线程
- p.start()
-
- def wait_p(self):
- for p in self.p_threadlst:
- p.join()
-
- def create_customer(self):
- for name in self.cname:
- c = Customer(self.dataqueue, name)
- self.c_threadlst.append(c)
- c.start()
-
- def wait_c(self):
- for c in self.c_threadlst:
- c.join()
生产者代码:
- class Producer(threading.Thread):
- '''
- 封装一下 chromedriver 无头浏览器参数
- '''
- options = Options()
- options.add_argument('--headless')
- options.add_argument('--disable-gpu')
-
- def __init__(self, data_queue, url_queue, name):
- super(Producer, self).__init__()
- self.data_queue = data_queue
- self.url_queue = url_queue
- self.name = name
-
- def run(self) -> None:
- '''
- 这里run方法主要实现两个方法 ① 下载页面 ② 将页面存到data_queue队列中
- :return: 这里的 ->None 表示返回的是空
- '''
- while not self.url_queue.empty():
- url = self.url_queue.get()
- # 下载页面
- print('我是{}---->>>>正在下载页面{}'.format(self.name, url.split('?')[1].split('&')[0]))
- self.download_html(url)
- print('我是{}---->>>>已完成下载页面{}'.format(self.name, url.split('?')[1].split('&')[0]))
-
- def download_html(self, url):
- # 创建一个浏览器对象
- browser = webdriver.Chrome('../chromedriver.exe', options=self.options)
- # 打开url
- browser.get(url)
- # 等待1秒
- time.sleep(1)
- # 处理弹出的按钮
- button = browser.find_element_by_css_selector('body > div.a-modal.risk-warning > div > div > button')
- # 点击按钮
- button.click()
- browser.implicitly_wait(3)
- # 等待js内容渲染
- time.sleep(2)
- # 将页面源码存入队列中
- self.data_queue.put(browser.page_source)
- # 最后最后一定要记得关闭浏览器! 因为这个函数是写在一个循环中的
- browser.quit()
消费者:
- class Customer(threading.Thread):
- # 初始化mongodb参数
- # 连接服务器
- conn = MongoClient(host='localhost', port=27017)
- # 创建数据库
- db = conn.zhaopin
- # 创建集合
- collection = db.zhaopin_collection
- # 创建一个锁对象 当一个线程进行数据库的写入时 锁上 存储信息完毕后释放
- lock = threading.Lock()
-
- def __init__(self, data_queue, name):
- super(Customer, self).__init__()
- self.data_queue = data_queue
- self.name = name
-
- def run(self) -> None:
- while True:
- try:
- # 获取页面内容进行解析
- content = self.data_queue.get(True, 20)
- print('我是{},我正在解析...'.format(self.name))
- self.parse_content(content)
-
- except Exception:
- print('我是{},已经完成解析...'.format(self.name))
- break
-
- def parse_content(self, content):
- '''
- 观察网站源码发现 所有的招聘内容放在了一个 div容器中 取出这个容器 循环遍历即可
- <div id="listContent" class="contentpile__content">
- :param content:
- :return:
- '''
- # 创建一个列表用于存储字典信息
- info_list = []
- soup = BeautifulSoup(content, 'lxml')
- div_lst = soup.find('div', id='listContent')
- for item in div_lst:
- try:
- # 岗位名称
- jobname = item.find('span', class_='contentpile__content__wrapper__item__info__box__jobname__title')[
- 'title']
- # 工资
- saray = item.find('p', class_='contentpile__content__wrapper__item__info__box__job__saray').text
- # 地区
- area = item.find_all('li', class_='contentpile__content__wrapper__item__info__box__job__demand__item')[
- 0].text
- # 经验
- ex = item.find_all('li', class_='contentpile__content__wrapper__item__info__box__job__demand__item')[
- 1].text.strip(), \
- item.find_all('li', class_='contentpile__content__wrapper__item__info__box__job__demand__item')[
- 2].text.strip()
- # 公司名
- company_name = item.find('a',
- class_='contentpile__content__wrapper__item__info__box__cname__title company_title').text
-
- # 将信息存储为字典
- item_info = {
- '岗位名称': jobname,
- '工资': saray,
- '地区': area,
- '经验': ex,
- '公司名': company_name
- }
- info_list.append(item_info)
-
- except Exception:
- continue
-
- # 写入数据库
- self.lock.acquire()
- self.collection.insert_many(info_list)
- self.lock.release()
-
最后的最后 贴上我爬取的部分信息吧~
----------------------------------------------------------------------------------------------------------------------------------------------------------
PS:优化一下代码,看看之前写的,啧啧,辣眼睛~
- # author:dayin
- # Date:2019/12/17 0017
- import time
- from selenium.webdriver.chrome.options import Options
- from selenium import webdriver
- from bs4 import BeautifulSoup
- from pymongo import MongoClient
- import threading
- from queue import Queue
-
- '''
- 需求: 输入起始页 和结束页 爬取智联招聘上python词条信息
- 爬取的信息包括 就业岗位名称 薪资 地区 公司名称 需求{包括学历和经验}
- 爬取的信息以字典形式保存到mongodb数据库中
- '''
- # 创建一个锁对象 当一个线程进行数据库的写入时 锁上 存储信息完毕后释放
- lock = threading.Lock()
- # 创建一个同步条件,用于任务结束的标志
- event = threading.Event()
-
-
- class ZhiLianSpider(object):
- # 定义类属性 生产者 和消费者
- pname = ['生产者1号', '生产者2号', '生产者3号', '生产者4号']
- cname = ['消费者1号', '消费者2号', '消费者3号']
-
- def __init__(self, start, end, urlqueue, dataqueue):
- self.start = start
- self.end = end
- self.url = r'https://sou.zhaopin.com/?p={}&jl=489&kw=python&kt=3&sf=0&st=0'
- self.urlqueue = urlqueue
- self.dataqueue = dataqueue
-
- # run 方法执行返回完整页面的url
- def run(self) -> None:
- for page in range(self.start, self.end + 1):
- self.urlqueue.put(self.url.format(page))
-
- def create_producer(self):
- '''
- 为了不使main函数中有太多冗余 将创建生产者和消费者放在这个类方法中
- :return:
- '''
- for name in self.pname:
- p = Producer(data_queue=self.dataqueue, url_queue=self.urlqueue, name=name)
- # 启动线程
- p.start()
-
- def create_customer(self):
- for name in self.cname:
- c = Customer(self.dataqueue, name)
- c.start()
-
-
- class Producer(threading.Thread):
- '''
- 封装一下 chromedriver 无头浏览器参数
- '''
- options = Options()
- options.add_argument('--headless')
- options.add_argument('--disable-gpu')
-
- def __init__(self, data_queue, url_queue, name):
- super(Producer, self).__init__()
- self.data_queue = data_queue
- self.url_queue = url_queue
- self.name = name
-
- def run(self) -> None:
- '''
- 这里run方法主要实现两个方法 ① 下载页面 ② 将页面存到data_queue队列中
- :return: 这里的 ->None 表示返回的是空
- '''
- while True:
- if self.url_queue.empty():
- event.set()
- break
- url = self.url_queue.get()
- # 下载页面
- print('我是{}---->>>>正在下载页面{}'.format(self.name, url.split('?')[1].split('&')[0]))
- self.download_html(url)
- print('我是{}---->>>>已完成下载页面{}'.format(self.name, url.split('?')[1].split('&')[0]))
-
- def download_html(self, url):
- # 创建一个浏览器对象
- browser = webdriver.Chrome('chromedriver.exe', options=self.options)
- # 打开url
- browser.get(url)
- # 等待1秒
- time.sleep(1)
- # 处理弹出的按钮
- button = browser.find_element_by_css_selector('body > div.a-modal.risk-warning > div > div > button')
- # 点击按钮
- button.click()
- browser.implicitly_wait(3)
- # 等待js内容渲染
- time.sleep(2)
- # 将页面源码存入队列中
- self.data_queue.put(browser.page_source)
- # 最后最后一定要记得关闭浏览器! 因为这个函数是写在一个循环中的
- browser.quit()
-
-
- class Customer(threading.Thread):
- # 初始化mongodb参数
- # 连接服务器
- conn = MongoClient(host='192.168.43.115', port=27017)
- # 创建数据库
- db = conn.zhaopin
- # 创建集合
- collection = db.zhaopin_collection
-
- def __init__(self, data_queue: Queue, name):
- super(Customer, self).__init__()
- self.data_queue = data_queue
- self.name = name
-
- def run(self) -> None:
- while True:
- # 获取页面内容进行解析
- if self.data_queue.empty() and event.is_set():
- print('任务完成...')
- break
- content = self.data_queue.get()
- print('我是{},我正在解析...'.format(self.name))
- self.parse_content(content)
- print('我是{},已经完成解析...'.format(self.name))
-
- def parse_content(self, content):
- '''
- 观察网站源码发现 所有的招聘内容放在了一个 div容器中 取出这个容器 循环遍历即可
- <div id="listContent" class="contentpile__content">
- :param content:
- :return:
- '''
- # 创建一个列表用于存储字典信息
- info_list = []
- soup = BeautifulSoup(content, 'lxml')
- div_lst = soup.find('div', id='listContent')
- try:
- for item in div_lst:
- try:
- # 岗位名称
- jobname = \
- item.find('span', class_='contentpile__content__wrapper__item__info__box__jobname__title')[
- 'title']
- # 工资
- saray = item.find('p', class_='contentpile__content__wrapper__item__info__box__job__saray').text
- # 地区
- area = \
- item.find_all('li', class_='contentpile__content__wrapper__item__info__box__job__demand__item')[
- 0].text
- # 经验
- ex = \
- item.find_all('li', class_='contentpile__content__wrapper__item__info__box__job__demand__item')[
- 1].text.strip(), \
- item.find_all('li', class_='contentpile__content__wrapper__item__info__box__job__demand__item')[
- 2].text.strip()
- # 公司名
- company_name = item.find('a',
- class_='contentpile__content__wrapper__item__info__box__cname__title company_title').text
-
- # 将信息存储为字典
- item_info = {
- '岗位名称': jobname,
- '工资': saray,
- '地区': area,
- '经验': ex,
- '公司名': company_name
- }
- info_list.append(item_info)
-
- except Exception:
- continue
- except Exception as e:
- print(e)
- # 写入数据库
- lock.acquire()
- self.collection.insert_many(info_list)
- lock.release()
-
-
- def main():
- startpage = eval(input('输入起始页码:'))
- endpage = eval(input('输入结束页码:'))
- # page 队列
- url_queue = Queue()
- # html 内容队列
- data_queue = Queue()
- spider = ZhiLianSpider(startpage, endpage, url_queue, data_queue)
- # 执行run方法返回一个url队列
- spider.run()
- # 创建生产者
- spider.create_producer()
- # 创建消费者
- spider.create_customer()
-
-
- if __name__ == '__main__':
- main()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。