最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python爬蟲實例——scrapy框架爬取拉勾網(wǎng)招聘信息

 更新時間:2020年07月14日 09:16:49   作者:Alex-GCX  
這篇文章主要介紹了Python爬蟲實例——scrapy框架爬取拉勾網(wǎng)招聘信息的相關(guān)資料,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下

本文實例為爬取拉勾網(wǎng)上的python相關(guān)的職位信息, 這些信息在職位詳情頁上, 如職位名, 薪資, 公司名等等.

分析思路

分析查詢結(jié)果頁

在拉勾網(wǎng)搜索框中搜索'python'關(guān)鍵字, 在瀏覽器地址欄可以看到搜索結(jié)果頁的url為: 'https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=', 嘗試將?后的參數(shù)刪除, 發(fā)現(xiàn)訪問結(jié)果相同.

打開Chrome網(wǎng)頁調(diào)試工具(F12), 分析每條搜索結(jié)果(即每個職位)在html中所處的元素定位, 發(fā)現(xiàn)每條結(jié)果都在<ul class="item_con_list">下的li標(biāo)簽中.

因為我們需要每個職位的具體信息, 因此需要獲取到每條搜索結(jié)果的詳情url, 即點擊搜索結(jié)果后進入的詳情頁的url.

繼續(xù)查看li標(biāo)簽中的元素, 找到想要的詳情url, 找到后的url為: href=https://www.lagou.com/jobs/6945237.html?show=b6e8e778fcae4c2aa2111ba58f9ebfa0

查看其它搜索結(jié)果的詳情url, 發(fā)現(xiàn)其格式都為: rel="external nofollow"

對于第一個ID, 每條結(jié)果的id都不一樣, 猜想其為標(biāo)記每個職位的唯一id, 對于show_id, 每條結(jié)果的id都是一樣的, 嘗試刪除show參數(shù), 發(fā)現(xiàn)一樣可以訪問到具體結(jié)果詳情頁

那么我們直接通過xpath提取到每個職位的第一個ID即可, 但是調(diào)試工具的elements標(biāo)簽下的html是最終網(wǎng)頁展示的html, 并不一定就是我們訪問 https://www.lagou.com/jobs/list_python 返回的response的html, 因此點到Network標(biāo)簽, 重新刷新一下頁面, 找到 https://www.lagou.com/jobs/list_python 對應(yīng)的請求, 查看其對應(yīng)的response, 搜索 'position_link'(即前面我們在elements中找到的每條搜索結(jié)果的詳情url), 發(fā)現(xiàn)確實返回了一個網(wǎng)址, 但是其重要的兩個ID并不是直接放回的, 而是通過js生成的, 說明我們想要的具體數(shù)據(jù)并不是這個這個請求返回的.

那么我們就需要找到具體是那個請求會返回搜索結(jié)果的信息, 一般這種情況首先考慮是不是通過ajax獲取的數(shù)據(jù), 篩選類型為XHR(ajax)的請求, 可以逐個點開查看response, 發(fā)現(xiàn) positionAjax.json 返回的數(shù)據(jù)中就存在我們想要的每條搜索結(jié)果的信息. 說明確實是通過ajax獲取的數(shù)據(jù), 其實點擊下一頁, 我們也可以發(fā)現(xiàn)地址欄url地址并沒有發(fā)生變化, 只是局部刷新了搜索結(jié)果的數(shù)據(jù), 也說明了搜索結(jié)果是通過ajax返回的.

分析上面ajax的response, 查看其中是否有我們想要的職位ID, 在preview中搜索之前在elements中找到的某個職位的url的兩個ID, 確實兩個ID都存在response中, 分析發(fā)現(xiàn)第一個ID即為positionId, 第二個即為showId, 我們還可以發(fā)現(xiàn)response中返回了當(dāng)前的頁碼數(shù)pageNo

因此我們只需要訪問上面ajax對應(yīng)的url: https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false 就可以拿到我們想要的ID, 然后填入詳情url模板: https://www.lagou.com/jobs/{position_id}.html?show={show_id}中即可訪問詳情頁了.

但是當(dāng)我們直接訪問 https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false 時 ,返回的結(jié)果卻是:  {"status":false,"msg":"您操作太頻繁,請稍后再訪問","clientIp":"139.226.66.44","state":2402}

經(jīng)過百度查詢后發(fā)現(xiàn)原來直接訪問上述地址是不行的, 這也是拉鉤的一個反爬策略, 需要我們帶上之前訪問查詢結(jié)果頁(https://www.lagou.com/jobs/list_python?)的cookie才行, 因為我們這里使用的是scrapy框架, 該框架是能夠自帶上次請求的cookie來訪問下一個請求的, 所以我們這里不需要手動去添加cookie信息, 只需要首先訪問一下查詢結(jié)果頁就可以了. 即start_url = https://www.lagou.com/jobs/list_python

此外發(fā)現(xiàn)這個ajax請求是通過POST方式發(fā)送的, 因此還需要分析它提交的form數(shù)據(jù), 在第一頁中有三條數(shù)據(jù)信息, first為true, pn為1 kd為python , 第二頁中first為false, pn為2, kd同樣為python, 且多了一個sid

分析這四個參數(shù), 第一個first為表示是否是第一頁, 第二個pn為表示當(dāng)前頁碼數(shù), 第三個kd為表示搜索的關(guān)鍵字, 第四個sid經(jīng)過和上面showId對比發(fā)現(xiàn)其值就為showId

分析職位詳情頁

前面分析完后就可以拼接出職位詳情頁url了, 點開詳情頁, 同樣的思路分析我們想要的數(shù)據(jù)是不是就在詳情頁的url中, 這里想要職位名稱, 工資, 地點, 經(jīng)驗, 關(guān)鍵字, 公司信息等

在network中查找對應(yīng)的response, 發(fā)現(xiàn)數(shù)據(jù)確實就存在response中, 因此直接通過xpath就可以提取想要的數(shù)據(jù)了

編寫爬蟲代碼

具體代碼在github:

這里只放出關(guān)鍵代碼

創(chuàng)建scrapy項目

scrapy startproject LaGou

創(chuàng)建爬蟲

scrapy genspider lagou www.lagou.com

編寫items.py, 設(shè)置要想爬取的字段

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy


class LagouItem(scrapy.Item):
 # define the fields for your item here like:
 job_url = scrapy.Field()
 job_name = scrapy.Field()
 salary = scrapy.Field()
 city = scrapy.Field()
 area = scrapy.Field()
 experience = scrapy.Field()
 education = scrapy.Field()
 labels = scrapy.Field()
 publish_date = scrapy.Field()
 company = scrapy.Field()
 company_feature = scrapy.Field()
 company_public = scrapy.Field()
 company_size= scrapy.Field()

編寫爬蟲代碼 lagou.py

# -*- coding: utf-8 -*-
import scrapy
from LaGou.items import LagouItem
import json
from pprint import pprint
import time


class LagouSpider(scrapy.Spider):
 name = 'lagou'
 allowed_domains = ['www.lagou.com']
 start_urls = ['https://www.lagou.com/jobs/list_python?']

 def __init__(self):
  # 設(shè)置頭信息, 若不設(shè)置的話, 在請求第二頁時即被拉勾網(wǎng)認(rèn)為是爬蟲而不能爬取數(shù)據(jù)
  self.headers = {
   "Accept": "application/json, text/javascript, */*; q=0.01",
   "Connection": "keep-alive",
   "Host": "www.lagou.com",
   "Referer": 'https://www.lagou.com/jobs/list_Python?',
   "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
   "referer": "https://www.lagou.com/jobs/list_python?"
  }
  self.sid = ''
  self.job_url_temp = 'https://www.lagou.com/jobs/{}.html?show={}'
  # 清空文件
  with open('jobs.json', 'w') as f:
   f.truncate()

 def parse(self, response):
  """
  解析起始頁
  """
  # response為GET請求的起始頁, 自動獲取cookie
  # 提交POST帶上前面返回的cookies, 訪問數(shù)據(jù)結(jié)果第一頁
  yield scrapy.FormRequest(
   'https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false',
   callback=self.parse_list,
   formdata={"first": "false",
      "pn": "1",
      "kd": "python",
      },
   headers=self.headers
  )
 def parse_list(self, response):
  """
  解析結(jié)果列表頁的json數(shù)據(jù)
  """
  # 獲取返回的json,轉(zhuǎn)為字典
  res_dict = json.loads(response.text)
  # 判斷返回是否成功
  if not res_dict.get('success'):
   print(res_dict.get('msg', '返回異常'))
  else:
   # 獲取當(dāng)前頁數(shù)
   page_num = res_dict['content']['pageNo']
   print('正在爬取第{}頁'.format(page_num))
   # 獲取sid
   if not self.sid:
    self.sid = res_dict['content']['showId']
   # 獲取響應(yīng)中的職位url字典
   part_url_dict = res_dict['content']['hrInfoMap']
   # 遍歷職位字典
   for key in part_url_dict:
    # 初始化保存職位的item
    item = LagouItem()
    # 拼接完整職位url
    item['job_url'] = self.job_url_temp.format(key, self.sid)
    # 請求職位詳情頁
    yield scrapy.Request(
     item['job_url'],
     callback=self.parse_detail,
     headers=self.headers,
     meta={'item': item}
    )

   # 獲取下一頁
   if page_num < 30:
    # time.sleep(2)
    yield scrapy.FormRequest(
     'https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false',
     callback=self.parse_list,
     formdata={"first": "false",
        "pn": str(page_num+1),
        "kd": "python",
        "sid": self.sid
        },
     headers=self.headers
    )

 def parse_detail(self, response):
  """
  解析職位詳情頁
  """
  # 接收item
  item = response.meta['item']
  # 解析數(shù)據(jù)
  # 獲取職位頭div
  job_div = response.xpath('//div[@class="position-content-l"]')
  if job_div:
   item['job_name'] = job_div.xpath('./div/h1/text()').extract_first()
   item['salary'] = job_div.xpath('./dd/h3/span[1]/text()').extract_first().strip()
   item['city'] = job_div.xpath('./dd/h3/span[2]/text()').extract_first().strip('/').strip()
   item['area'] = response.xpath('//div[@class="work_addr"]/a[2]/text()').extract_first()
   item['experience'] = job_div.xpath('./dd/h3/span[3]/text()').extract_first().strip('/').strip()
   item['education'] = job_div.xpath('./dd/h3/span[4]/text()').extract_first().strip('/').strip()
   item['labels'] = response.xpath('//ul[@class="position-label clearfix"]/li/text()').extract()
   item['publish_date'] = response.xpath('//p[@class="publish_time"]/text()').extract_first()
   item['publish_date'] = item['publish_date'].split('&')[0]
   # 獲取公司dl
   company_div = response.xpath('//dl[@class="job_company"]')
   item['company'] = company_div.xpath('./dt/a/img/@alt').extract_first()
   item['company_feature'] = company_div.xpath('./dd//li[1]/h4[@class="c_feature_name"]/text()').extract_first()
   item['company_feature'] = item['company_feature'].split(',')
   item['company_public'] = company_div.xpath('./dd//li[2]/h4[@class="c_feature_name"]/text()').extract_first()
   item['company_size'] = company_div.xpath('./dd//li[4]/h4[@class="c_feature_name"]/text()').extract_first()
   yield item

編寫middlewares.py, 自定義downloadermiddleware, 用來每次發(fā)送請求前, 隨機設(shè)置user-agent, 這里使用了第三方庫 fake_useragent, 能夠隨機提供user-agent, 使用前先安裝: pip install fake_useragent

from fake_useragent import UserAgent
import random

class RandomUserAgentDM:
 """
 隨機獲取userAgent
 """
 def __init__(self):
  self.user_agent = UserAgent()

 def process_request(self, request, spider):
  request.headers['User-Agent'] = self.user_agent.random

編寫pipelines.py, 將數(shù)據(jù)存為json文件

import json

class LagouPipeline:
 def process_item(self, item, spider):
  with open('jobs.json', 'a', encoding='utf-8') as f:
   item_json = json.dumps(dict(item), ensure_ascii=False, indent=2)
   f.write(item_json)
   f.write('\n')

編寫settings.py

# 設(shè)置日志顯示
LOG_LEVEL = 'WARNING'

# 設(shè)置ROBOTSTXT協(xié)議, 若為true則不能爬取數(shù)據(jù)
ROBOTSTXT_OBEY = False

# 設(shè)置下載器延遲, 反爬蟲的一種策略
DOWNLOAD_DELAY = 0.25

# 開啟DOWNLOADER_MIDDLEWARES
DOWNLOADER_MIDDLEWARES = {
 # 'LaGou.middlewares.LagouDownloaderMiddleware': 543,
 'LaGou.middlewares.RandomUserAgentDM' :100,
}

# 開啟ITEM_PIPELINES
ITEM_PIPELINES = {
 'LaGou.pipelines.LagouPipeline': 300,
}

啟動爬蟲

scrapy crawl lagou

發(fā)現(xiàn)依然只能5 6頁, 說明拉勾網(wǎng)的反爬確實做得比較好, 還可以繼續(xù)通過使用代理來進行反反爬, 這里就不再演示了,

查看爬取結(jié)果

以上就是Python爬蟲實例——scrapy框架爬取拉勾網(wǎng)招聘信息的詳細(xì)內(nèi)容,更多關(guān)于Python爬蟲爬取招聘信息的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • python使用elasticsearch的過程詳解

    python使用elasticsearch的過程詳解

    Elasticsearch 是一個開源的搜索引擎,建立在一個全文搜索引擎庫 Apache Lucene基礎(chǔ)之上,這篇文章主要介紹了python使用elasticsearch的詳細(xì)過程,需要的朋友可以參考下
    2024-03-03
  • 解決python 讀取excel時 日期變成數(shù)字并加.0的問題

    解決python 讀取excel時 日期變成數(shù)字并加.0的問題

    這篇文章主要介紹了python 讀取excel時, 日期變成數(shù)字并加.0的問題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-10-10
  • Python類和對象基礎(chǔ)入門介紹

    Python類和對象基礎(chǔ)入門介紹

    Python 是一種面向?qū)ο蟮木幊陶Z言。Python 中的幾乎所有東西都是對象,擁有屬性和方法。類(Class)類似對象構(gòu)造函數(shù),或者是用于創(chuàng)建對象的藍圖
    2022-08-08
  • python實現(xiàn)超市管理系統(tǒng)(后臺管理)

    python實現(xiàn)超市管理系統(tǒng)(后臺管理)

    這篇文章主要為大家詳細(xì)介紹了python實現(xiàn)超市管理系統(tǒng),增加后臺管理,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • python Multiprocessing.Pool進程池模塊詳解

    python Multiprocessing.Pool進程池模塊詳解

    multiprocessing模塊提供了一個Process類來代表一個進程對象,multiprocessing模塊像線程一樣管理進程,這個是multiprocessing的核心,它與threading很相似,對多核CPU的利用率會比threading好的多
    2022-10-10
  • Python isalnum()函數(shù)的具體使用

    Python isalnum()函數(shù)的具體使用

    本文主要介紹了Python isalnum()函數(shù)的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • python logging 重復(fù)寫日志問題解決辦法詳解

    python logging 重復(fù)寫日志問題解決辦法詳解

    這篇文章主要介紹了python logging 重復(fù)寫日志問題解決辦法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • numpy中生成隨機數(shù)的幾種常用函數(shù)(小結(jié))

    numpy中生成隨機數(shù)的幾種常用函數(shù)(小結(jié))

    這篇文章主要介紹了numpy中生成隨機數(shù)的幾種常用函數(shù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Python使用Flask-SQLAlchemy連接數(shù)據(jù)庫操作示例

    Python使用Flask-SQLAlchemy連接數(shù)據(jù)庫操作示例

    這篇文章主要介紹了Python使用Flask-SQLAlchemy連接數(shù)據(jù)庫操作,簡單介紹了flask、Mysql-Python以及Flask-SQLAlchemy的安裝方法,并結(jié)合實例形式分析了基于Flask-SQLAlchemy的數(shù)據(jù)庫連接相關(guān)操作技巧,需要的朋友可以參考下
    2018-08-08
  • 淺談numpy生成數(shù)組的零值問題

    淺談numpy生成數(shù)組的零值問題

    今天小編就為大家分享一篇淺談numpy生成數(shù)組的零值問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-11-11

最新評論

靖宇县| 古田县| 新源县| 鄂托克前旗| 新河县| 印江| 松溪县| 新干县| 定襄县| 桃园市| 徐州市| 鹤峰县| 乐业县| 澄迈县| 黄浦区| 梁山县| 山西省| 上高县| 平邑县| 张家界市| 斗六市| 隆昌县| 寿阳县| 建宁县| 美姑县| 神池县| 上杭县| 西藏| 富阳市| 增城市| 崇明县| 四川省| 白河县| 克山县| 偏关县| 邹平县| 彭山县| 北辰区| 德江县| 和静县| 江源县|