美文网首页
拉勾网职位列表爬取

拉勾网职位列表爬取

作者: 南太湖小蚂蚁 | 来源:发表于2019-06-21 15:25 被阅读0次

        三个小爬虫的最后一个是对拉勾网职位列表的爬取,当然这里没有考虑增量爬取,也没有考虑多线程爬取,仅仅是简单的把职位列表抓取下来并存储到数据库中。

设计思路如下:
  1. 访问拉勾网首页,获取默认的职位类型名称和链接


    首页职位类型列表
  2. 模拟点击其中某一类型的职位,并对展现的职位列表信息进行抓取


    职位列表

采用的工具包括urllib和selenium。

下面详细分解我是怎么做的(可能不一定对)

首先,是搞定首页。为什么要用urllib而不直接使用selenium呢,因为我发现直接用selenium的话,获取的页面信息中,只有默认的职位类型,没有后面的详细类型,必须要鼠标移动上去后才可以展现出后面的详细类型。(后来发现其实是隐藏在class是menu_sub这个div中的)



这样就比较麻烦了,无法获取完整的类型列表,当然我可以在selenium打开js功能,使用js来模拟鼠标移动上去等功能,这样我觉得比较麻烦,还不如直接用urllib去获取了。其次,我发现,如果是selenium模拟打开首页,拉勾网还会弹出一个页面让你选择具体的地方网站还是全国站,selenium还需要模拟点击一下全国站,当然这都不是难事,不过我嫌麻烦:) selenium打开首页

好了,那么我们就用urllib来获取,这里先定义一个下载页面的工具函数:

def download(url, user_agent='balabala', num_retries=2):
    print("Downloading: ", url)
    print('num_retries: ', num_retries)
    user_agent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"
    headers = {'User-agent': user_agent}
    request = urllib.request.Request(url, headers=headers)
    try:
        html = urllib.request.urlopen(request).read()
    except urllib.error.URLError as e:
        print("Download Error: ", e.reason)
        html = None
        # 如果是服务器端问题的话就重复尝试,直到超过三次
        if num_retries > 0:
            if hasattr(e, 'code') and 500 <= e.code < 600:
                return download(url, num_retries - 1)
    html = html.decode('utf-8')
    return html

user_agent我在代码中指定了,当然调用的时候可以传进来你自己定义的agent。num_retries代表的是重复访问的次数,意思是尝试访问这个网页url的次数,我这里使用了一个异常处理模块,如果访问URL的时候出错了,那么判断是否是5**的错误,这种错误是服务器内部错误,如果是这种错误,那么说明地址是对的,只是服务器出问题了,那么我重复访问num_retries次,如果还是没有信息那么只有范围None了,当然如果是400之类错误,那就是直接返回None的。

好了,现在有了访问函数了,我们就可以开始访问首页了。获取页面后用美味汤(BeautifulSoup)来解析,先prettify一下来看看,这里太长就不打印了。

data = download('https://www.lagou.com/')
soup = BeautifulSoup(data, "lxml")
# print(soup.prettify())  

其实,用Chrome看一下的话,这个套路就清清楚楚了。很明显,就是class = "menu_sub dn"这个div先的dl节点列表


那接着就是干了,获取这个menu_sub的列表,遍历每个menu_sub,获取到每个menu中的每个链接a的名称以及地址即可。

menus = soup.select('.menu_sub')

for menu in menus:
    hrefs = menu.select('a')
    for href in hrefs:
        print("%s, %s" % (href.text, href.attrs['href']))

结果如下:


职位类型列表

好了,下一步就是访问这些职位类型的详情列表获取职位信息了。这里我换成了selenium访问具体的页面。

def crawl(url, browser):
    print('抓取地址:%s' % url)
    conn = initDB() # 初始化数据库连接
    # 访问首页
    browser.get(url)
    browser.find_element_by_id('submit').click()
    time.sleep(5)  # 留出加载页面时间,同时也为了不给服务器太大压力
    print(browser.current_url)
    jobList = browser.find_elements_by_class_name('con_list_item')

这里有个小问题,如果用selenium访问职位列表URL,有时候会被拉勾网识别到,并列出初始化的职位列表,得不到我们请求的职位列表,所以我获取到页面的提交按钮,发送一个click()事件,等于是点了一下“搜索”按钮,返回的就一定是我们需要的职位列表了。


获取到数据后,我们就可以用selenium来解析了。可以看到每个职位列表被一个class为"con_list_item default_list"的li列表包围着


获取到职位列表后,我们遍历这个列表,取出相应职位名称,工作地点,企业名称,薪水,学历要求等信息,并存储到数据库中

        for job in jobList:
            jobName = job.find_element_by_tag_name('h3').text
            location = job.find_element_by_class_name('add').text
            money = job.find_element_by_class_name('money').text
            education = job.find_element_by_class_name('li_b_l').text
            education = education.replace(money, '')
            company = job.find_element_by_class_name('company_name').text
            print("jobName: %s, location: %s, money: %s, education: %s, company: %s" % (
            jobName, location, money, education, company))
            saveDB(conn, jobName, location, money, education, company)
职位详情

接下来,还要一步,就是翻页。当遍历完当前的职位列表后,需要继续访问下一页的内容(如果有的话),我们查看一下“下一页”链接

下一页
好了,只要获取这个链接,并发送click事件就可以翻页了,如果到了最后一页是怎么样的呢?
最后一页
可以看到,这里的class除了"pager_next"还多了一个"pager_next_disabled",当找到这个节点后,我们就可以跳出循环了。
当然,还有一种情况,就是第一页就没有"pager_next",为什么呢?因为这个类型的工作职位很少啊,连一页都填不满,就像下面图片中显示的那样,所以我们需要单独处理下,否则会报错。(这里我发现一个问题就是如果你直接访问前面menu_sub中获取的URL链接,可能再少的工作职位也会显示“下一页”,但是我是模拟点击“搜索”后的,就没有“下一页”按钮了,这些都是拉勾网的设计了,我们只能去适应它。
直接访问menu_sub中的链接的有“下一页” 模拟点击“搜索”后,没有下一页的情况

发现区别了吗?
综合起来,翻页的代码如下:

        try:
            next_page = browser.find_element_by_class_name('pager_next')  # 如果这句话抛出异常,说明没有下一页,工作很少,那么就直接返回,退出当前工作类别的爬取
        except Exception as err:
            return
        while next_page:
            try:
                browser.find_element_by_class_name('pager_next_disabled') # 注意这里不能用if-else判断,否则在获取这个节点的时候就会报错
                break
            except NoSuchElementException as err:
                next_page.click()
                time.sleep(5)  # 加载
                jobList = browser.find_elements_by_class_name('con_list_item')

                for job in jobList:
                    jobName = job.find_element_by_tag_name('h3').text
                    location = job.find_element_by_class_name('add').text
                    money = job.find_element_by_class_name('money').text
                    education = job.find_element_by_class_name('li_b_l').text
                    # print(type(education))
                    education = education.replace(money, '')
                    company = job.find_element_by_class_name('company_name').text
                    print("jobName: %s, location: %s, money: %s, education: %s, company: %s" % (
                        jobName, location, money, education, company))
                    saveDB(conn, jobName, location, money, education, company)
                next_page = browser.find_element_by_class_name('pager_next')
                time.sleep(10)

完整代码如下:
lagou.py,核心抓取函数

from selenium import webdriver
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
import time
import urllib.request
import urllib.error
import re
from selenium.webdriver.common.touch_actions import TouchActions
from selenium.webdriver.common.keys import Keys
from bs4 import BeautifulSoup
import psycopg2

def initDB():  #  初始化数据连接
    conn = psycopg2.connect(database="spider", user="postgres", password="kfbserver203.", host="127.0.0.1", port="5432")
    return conn

def closeDB(conn):  #  关闭数据库连接
    conn.close()

def saveDB(conn, jobName, location, money, education, company):  #  存储数据
    cur = conn.cursor()
    cur.execute(
        "INSERT INTO job (job_name,location,money,education,company) VALUES ('" + jobName + "','" + location + "','" + money + "','" + education + "','" + company + "')")
    conn.commit()

def crawl(url, browser):
    print('抓取地址:%s' % url)
    conn = initDB()
    # 访问首页
    # browser.get('https://www.lagou.com/zhaopin/shenduxuexi/?filterOption=3')
    browser.get(url)
    result = []
        
    # href_e = browser.find_element_by_link_text('全国站')
    browser.find_element_by_id('submit').click()
    time.sleep(5)
    print(browser.current_url)
    jobList = browser.find_elements_by_class_name('con_list_item')

    for job in jobList:
        jobName = job.find_element_by_tag_name('h3').text
        location = job.find_element_by_class_name('add').text
        money = job.find_element_by_class_name('money').text
        education = job.find_element_by_class_name('li_b_l').text
        # print(type(education))
        education = education.replace(money, '')
        company = job.find_element_by_class_name('company_name').text
        print("jobName: %s, location: %s, money: %s, education: %s, company: %s" % (
        jobName, location, money, education, company))
        saveDB(conn, jobName, location, money, education, company)
    try:
        next_page = browser.find_element_by_class_name('pager_next')  # 如果这句话抛出异常,说明没有下一页,工作很少,那么就直接返回,退出当前工作类别的爬取
    except Exception as err:
        return
    while next_page:
        try:
            browser.find_element_by_class_name('pager_next_disabled')
            break
        except NoSuchElementException as err:
            next_page.click()
            time.sleep(5)  # 加载
            jobList = browser.find_elements_by_class_name('con_list_item')

            for job in jobList:
                jobName = job.find_element_by_tag_name('h3').text
                location = job.find_element_by_class_name('add').text
                money = job.find_element_by_class_name('money').text
                education = job.find_element_by_class_name('li_b_l').text
                # print(type(education))
                education = education.replace(money, '')
                company = job.find_element_by_class_name('company_name').text
                print("jobName: %s, location: %s, money: %s, education: %s, company: %s" % (jobName, location, money, education, company))
                saveDB(conn, jobName, location, money, education, company)
            next_page = browser.find_element_by_class_name('pager_next')
            time.sleep(10)

    closeDB(conn)  # 关闭数据库

lagou2.py,抓取职位类型,创建selenium webdriver对象,调用抓取程序

from selenium import webdriver
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
import time
import urllib.request
import urllib.error
import urllib.parse
from http import cookiejar
import re
from selenium.webdriver.common.touch_actions import TouchActions
from selenium.webdriver.common.keys import Keys
from bs4 import BeautifulSoup
import lagou
'''
获取各种默认搜索关键字和链接
'''

# 直接下载页面
def download(url, user_agent='wswp', num_retries=2):
    print("Downloading: ", url)
    print('num_retries: ', num_retries)
    user_agent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"
    headers = {'User-agent': user_agent}
    request = urllib.request.Request(url, headers=headers)
    try:
        html = urllib.request.urlopen(request).read()
    except urllib.error.URLError as e:
        print("Download Error: ", e.reason)
        html = None
        # 如果是服务器端问题的话就重复尝试,直到超过三次
        if num_retries > 0:
            if hasattr(e, 'code') and 500 <= e.code < 600:
                return download(url, num_retries - 1)
    html = html.decode('utf-8')
    return html

data = download('https://www.lagou.com/')
soup = BeautifulSoup(data, "lxml")
# print(soup.prettify())
menus = soup.select('.menu_sub')

browser = webdriver.Chrome("C://Drivers/chromedriver_win32/chromedriver.exe")

for menu in menus:
    hrefs = menu.select('a')
    for href in hrefs:
        print("%s, %s" % (href.text, href.attrs['href']))
        lagou.crawl(href.attrs['href'], browser)
程序执行结果 数据库存储抓取的数据

相关文章

  • 拉勾网职位列表爬取

    三个小爬虫的最后一个是对拉勾网职位列表的爬取,当然这里没有考虑增量爬取,也没有考虑多线程爬取,仅仅是简单的把职位列...

  • 拉勾爬虫实战

    0 引言   一次简单的 Python 爬虫练习:输入 目标城市 和 目标职位,从 拉勾网 爬取相关的职位列表数据...

  • 拉勾网职位信息爬取

    分析网页 通过浏览器查看网页源代码,未能找到职位信息,因此需要打开F12开发者工具抓包分析职位数据使怎样被加载到网...

  • 拉勾网前端职位数据分析(Excel,Python工具)

    一、使用scrpy爬取拉勾网(厦门地区)前端职位数据数据爬取过程可以参考慕课网教程。 使用Excel数据透视表(样...

  • Selenium小例子

    爬取腾讯动漫 爬取某网站漫画 爬取拉勾网

  • 数据分析师薪酬?拉勾网职位爬取+分析

    ——2018.06.01——最近几天看到了很多文章写拉勾网职位爬取,那些基本是基于requests + json,...

  • Python爬虫-拉勾网职位爬取

    感觉好久没写python了哈哈,最近都在忙工作,所以也是没有学习python。刚好凑巧朋友正在找工作,也是java...

  • requests + Beautiful爬取拉勾网职位

    这次的案例中我们会接触到Ajax动态加载的网页,可以看到,包括下一页等很多信息块都没有链接出线,所以就页数遍历上面...

  • 爬取拉勾招聘职位

    爬取拉勾招聘职位 import json import pymysql import requests from ...

  • Python urllib爬取拉勾网职位信息

    为了获取拉勾网的招聘信息,对数据分析岗位的基本信息进行爬取。之所以选择拉勾网作为本项目的数据源,主要是因为相对于其...

网友评论

      本文标题:拉勾网职位列表爬取

      本文链接:https://www.haomeiwen.com/subject/okweqctx.html