for-technology-lover

更新说明

上一版本地址
由于爬取的原网站的变化,当前数据是在JavaScript中,浏览器会对JavaScript代码进行渲染,然后再呈现。然而,当我们通过爬虫程序获取数据时,爬虫程序并不能自动对HTML文件中的JavaScript代码进行渲染。因此,需要获取JS中数据进行解析。

程序说明

通过爬取“51job”获取招聘信息(以计算机软件为例),根据所获取数据分析领域相关工作职位需求,并通过可视化的方式展示分析行业就业情况(例如平均月薪、工作地点等)。

数据爬取

使用requests库请求网页内容,使用BeautifulSoup4正则表达库re解析网页。

观察网页结构

首先在爬取网页前,使用使用浏览器“开发者工具”,观察网页结构。
页面结构

页面解析

使用beautifulsoup解析页面,获取JS中所需数据:

soup.find_all(\'script\')[7]

为了能够使用re解析获取内容,需要将内容转换为字符串:

results = str(soup.find_all(\'script\')[7])

例如为了获取工作名,首先构造正则表达式:

pattern = re.compile(r"job_name":"\'(.*?)\'",re.MULTILINE|re.DOTALL)

然后查找所有的工作名:

job_names = pattern_job_name.findall(results)

为了方便获取所需字段,构造解析函数

def analysis(item,results):
    pattern = re.compile(item, re.I|re.M)
    result_list = pattern.findall(results)
    return result_list

将数据写入csv文件中

观察解析出的数据,例如公司名地址:

https:\/\/jobs.51job.com\/all\/co6371981.html

例如工作名:

Trade Ops(Contractor, Operations)

为了将数据写入csv文件中,首先需要将获得数据中的逗号\',\'去除,因为其表示单元格的切换,然后还需去掉结果中的转义字符/
因此将获取的数据进行预处理:

def precess(item):
    return item.replace(\',\', \' \').replace(\'\\\', \'\')

通过观察页面链接,爬取所有页面

查看第2页链接为:

https://search.51job.com/list/000000,000000,0000,00,9,99,%25E8%25AE%25A1%25E7%25AE%2597%25E6%259C%25BA,2,2.html?lang=c&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&ord_field=0&dibiaoid=0&line=&welfare=

第3页链接为:

https://search.51job.com/list/000000,000000,0000,00,9,99,%25E8%25AE%25A1%25E7%25AE%2597%25E6%259C%25BA,2,3.html?lang=c&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&ord_field=0&dibiaoid=0&line=&welfare=

仅改变了页面数字,因此可以构造如下模式,并使用循环,爬取所有页面:

url_pattern = "https://search.51job.com/list/000000,000000,0000,00,9,99,%25E8%25AE%25A1%25E7%25AE%2597%25E6%259C%25BA,2,{}.html?lang=c&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&ord_field=0&dibiaoid=0&line=&welfare="
for i in range(1,2001):
    url = url_pattern.format(i)

爬虫程序完整代码

import time
import requests
from bs4 import BeautifulSoup
import os
import csv
import re

def analysis(item,results):
    pattern = re.compile(item, re.I|re.M)
    result_list = pattern.findall(results)
    return result_list

def precess(item):
    return item.replace(\',\', \' \').replace(\'\\\', \'\')

#构建请求头
headers = {
    \'User-Agent\':\'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:86.0) Gecko/20100101 Firefox/86.0\'
}
url_pattern = "https://search.51job.com/list/000000,000000,0000,00,9,99,%25E8%25AE%25A1%25E7%25AE%2597%25E6%259C%25BA,2,{}.html?lang=c&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&ord_field=0&dibiaoid=0&line=&welfare="

if not os.path.exists("intro_job.csv"):
    #创建存储csv文件存储数据
    file = open(\'intro_job.csv\', "w", encoding="utf-8-sig",newline=\'\')
    csv_head = csv.writer(file)
    #表头
    header = [\'job\',\'company\',\'place\',\'salary\',\'date\',\'detail_url\']
    csv_head.writerow(header)
    file.close()
    
for i in range(1,2001):
    #增加时延防止反爬虫
    time.sleep(5)
    url = url_pattern.format(i)
    response = requests.get(url=url, headers=headers)
    
    #声明网页编码方式,需要根据具体网页响应情况
    response.encoding = \'gbk\'
    response.raise_for_status()
    soup = BeautifulSoup(response.text, \'html.parser\')
    #pattern = re.compile(r"engine_search_result\'(.*?)\'",re.MULTILINE|re.DOTALL)
    results = str(soup.find_all(\'script\')[7])
    job_names  = analysis(r\'"job_name":"(.*?)"\', results)
    company_names = analysis(r\'"company_name":"(.*?)"\', results)
    workarea_texts = analysis(r\'"workarea_text":"(.*?)"\', results)
    providesalary_texts = analysis(r\'"providesalary_text":"(.*?)"\', results)
    updatedates = analysis(r\'"updatedate":"(.*?)"\', results)
    job_hrefs = analysis(r\'"job_href":"(.*?)"\', results)
    for i in range(len(job_names)):
        with open(\'intro_job.csv\', \'a+\', encoding=\'utf-8-sig\') as f:
            f.write(precess(job_names[i]) + \',\' 
                    + precess(company_names[i]) + \',\' 
                    + precess(workarea_texts[i]) + \',\' 
                    + precess(providesalary_texts[i]) + \',\' 
                    + precess(updatedates[i]) +\',\' 
                    + precess(job_hrefs[i]) + \'\n\')

爬取数据结果

展示部分爬取结果:
部分数据展示

数据及可视化

该部分参考之前博客

The end

Enjoying coding!

分类:

技术点:

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-12-05
  • 2021-12-04
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-05-21
  • 2022-12-23
  • 2021-12-26
  • 2021-11-25
  • 2021-11-28
  • 2021-10-16
  • 2021-09-07
相关资源
相似解决方案