【python】多进程+多线程 制作智联招聘爬虫 写入CSV+mongodb

前期准备:

这次爬虫用的都是python自带的包,所以只用准备一个pymongo用于mongodb数据库连接就可以了

pip install pymongo


第一步:目标站点分析

url = ‘http://sou.zhaopin.com/jobs/searchresult.ashx?p=0&jl=%E5%85%A8%E5%9B%BD&kw=%E5%A4%A7%E6%95%B0%E6%8D%AE&isadv=0’




        观察上面url 可以发现 智联招聘用4个参数定义了搜索的范围  其中 P 为 page 也就是页码。jl 为地域范围 这里是全国,KW 为搜索内容 这里我搜索的是关于大数据方面的,isadv这个我没去研究。不过对搜索没有影响。

      

 所以,我们可以通过这个定制搜索的内容来得到索引页的url  :


def get_page_index(jl,keyword,page=1):
    data = {
    'jl':jl,
    'kw':keyword,
    'p':page,
    'isadv': 0
    }
    url = 'http://sou.zhaopin.com/jobs/searchresult.ashx?'+ urlencode(data)
    print('[+] 到达索引页: %s' % url)
    return download_html(url)

再设置一个confi脚本,将其引入爬取智联招聘.py文件中。

from config import *


二步:解析索引页中所有职位的url

智联招聘的每个职位url:

示例:http://jobs.zhaopin.com/208149611251243.htm

http://jobs.zhaopin.com/407340480250023.htm

http://jobs.zhaopin.com/390314230250020.htm

观察上面职位url,可以发现 都是由http://jobs.zhaopin.com/+15位数字+.htm 组成

通过这个,我们可以用re模块将页面所有的url连接解析出来,然后再匹配满足上面示例形式的url。




具体代码如下:


def get_index_href(html):
    pattern = re.compile('<a[^>]+href=["\'](.*?)["\']', re.IGNORECASE)
    links = pattern.findall(html)
    href = 'http://jobs.zhaopin.com/\d{15}.htm'
    for link in links:  # 取到所有的a标签中的链接,
        if re.match(href, link) :  # 进行匹配
            yield link
    return None

第三步:进入职位的url抓取职位信息

 



我们需要的是上面的这些信息。




查看网页源代码,智联招聘对爬虫来说很友好,每个我们需要的内容都包含在<strong>标签下,我们很容易通过正则表达式把所有的需要的信息抓取下来。这里推荐大家一个在线的正则表达式网站:在线正则表达式测试




我用来匹配的表达式:


pattern = '<li><span>[\u4e00-\u9fa5 :]+</span>.*?>([\u4e00-\u9fa5 :\w\s/-]+).*>'

tittle_pattern = '<h1>([\u4e00-\u9fa5 :+、()\.\w\s/-]+.*?)</h1>'


第四步: 循环


      循环其实在爬虫中是很好理解和琢磨的,所以这里就不再介绍了。最后我们把爬下来的数据写入mongodb和csv文件中,用在后续的机器学习数据分析。

csv文件的写入示例:


import csv
with open("name.csv", "w") as csvfile:
 # 写标题
   fileheader = ["name", "score"]
    dict_writer = csv.DictWriter(csvFile, fileheader)
 # 写数据名,可以自己写如下代码完成:
    dict_writer.writerow(dict(zip(fileheader, fileheader)))
 # 之后,按照(属性:数据)的形式,将字典写入CSV文档即可
    dict_writer.writerow({"name": "Li", "score": "80"})
  
第五步:引入多线程与多进程

    

 写模块的时候,一般多进程和多线程用在 if __name__ == '__main__'之后,前后对比一下,因为python的线程锁GIL,其实多线程并不会有很好的效果,不过对于多核的处理器多进程确实会提高很多效率。在python中多线程和多进程使用方法很简单。


    #多线程
    pool = multiprocessing.Pool()
    # 多进程
    thread = threading.Thread(target=pool.map,args = (main,[x for x in range(1, 100)]))
    thread.start()
    thread.join()



实例代码:


import csv,re,threading,multiprocessing
from urllib.parse import urlencode
from urllib.request import urlopen,Request,urlparse,build_opener,install_opener
from  urllib.error import URLError,HTTPError
import pymongo as pymongo
from config import *

def download_html(url):
    headers = {'User-Agent': "User-Agent:Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)"}
    request = Request(url, headers=headers)
    try:
        html = urlopen(request).read().decode()
    except HTTPError as e:
        html = None
        print('[W] 下载出现服务器错误: %s' % e.reason)
        return None
    except URLError as e:
        html = None
        print("[E] 站点不可达: %s" % e.reason)
        return None
    return html

def get_page_index(jl,keyword,page=1):
    data = {
    'jl':jl,
    'kw':keyword,
    'p':page,
    'isadv': 0
    }
    url = 'http://sou.zhaopin.com/jobs/searchresult.ashx?'+ urlencode(data)
    print('[+] 到达索引页: %s' % url)
    return download_html(url)

def get_index_href(html):
    pattern = re.compile('<a[^>]+href=["\'](.*?)["\']', re.IGNORECASE)
    links = pattern.findall(html)
    href = 'http://jobs.zhaopin.com/\d{15}.htm'
    for link in links:  # 取到所有的a标签中的链接,
        if re.match(href, link) :  # 进行匹配
            yield link
    return None

def page_parser(html,fileheader):
    pattern = '<li><span>[\u4e00-\u9fa5 :]+</span>.*?>([\u4e00-\u9fa5 :\w\s/-]+).*>'
    data = re.findall(pattern,html)


    try:
        tittle_pattern = '<h1>([\u4e00-\u9fa5 :+、()\.\w\s/-]+.*?)</h1>'
        tittle_find = re.search(tittle_pattern, html)
        tittle = tittle_find.group(1)
        data.insert(0, tittle)
    except:
        print('职业名称未找到')
        data.insert(0,'大数据职位')
    clear_data = dict(zip(fileheader,data))
    return clear_data

def writer_to_mongodb(res):
    if db[MONGOTABE].insert(res):
        print('herf= {} save success'.format(url))
        return True
    print('save fail')
    return False

def write_csv_header(fileheader):
    with open("智联招聘.csv", "w",newline='') as csvfile:
        writer = csv.DictWriter(csvfile, fileheader)
        writer.writeheader()

def main(page):
    fileheader = ['职位名称','职位月薪', '工作地点', '发布日期', '工作性质', '工作经验', '最低学历', '招聘人数', '职位类别', '公司规模', '公司性质', '公司行业']
    html = get_page_index(jl,keyword,page)
    for link in get_index_href(html):
        print('[+] 找到目标站点: %s' % link)
        parser_html = download_html(link)
        dict = page_parser(parser_html,fileheader)

        #写入数据库 mongodb
        #writer_to_mongodb(dict)

        with open("智联招聘.csv", "a",newline='') as csvfile:
            print('    正在写入csv文件中.....')
            writer = csv.DictWriter(csvfile, fieldnames=fileheader)
            writer.writerow(dict)

if __name__ == '__main__':
    client = pymongo.MongoClient(MONGO_URL)
    db = client[MONGODB]
    fileheader = ['职位名称','职位月薪', '工作地点', '发布日期', '工作性质', '工作经验', '最低学历', '招聘人数', '职位类别', '公司规模', '公司性质', '公司行业']
    write_csv_header(fileheader)
    #多线程
    pool = multiprocessing.Pool()
    # 多进程
    thread = threading.Thread(target=pool.map,args = (main,[x for x in range(1, 100)]))
    thread.start()
    thread.join()


效果展示:



猜你喜欢

转载自blog.csdn.net/qq_41664845/article/details/79255225