本次主要内容是分享下拉勾网站模拟搜索以及搜索内容的爬取,这里先引入一些用到的库,由于网站本身的反爬虫技术和网络原因,这里使用了fake_useragent和多线程模式,当然如果有条件的话也可以使用代理池,这样可以更加保险一点。由于我没有弄那些收费的代理,而免费的代理有时会出现问题,所有就没有使用。

import requests
import json
import pymongo
from bs4 import BeautifulSoup
from fake_useragent import UserAgent
import time
from requests.exceptions import RequestException
import threading
from queue import Queue

首先通过分析网页network工作情况可知,拉勾的搜索页面是运用的ajax技术,所以首先要找到数据接口网址,作为post数据的初始网址,然后分析所带的参数,通过分析可以first的值和pn键的值对应的关系,可以使用一个判断语句控制,内容如下:

url="https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false"
tag = "true" if pn == 1 else "false"
data = {
            'first': true,
            'pn': 1,
            'kd':python
        }

然后就是在返回的包中提取内容,通过分析包可以知道搜索返回的数据,找到需要的数据。这里由于我们需要进入每个搜索内容的详情页,所以我们需要获得搜索内容返回的页面的id,然后进行字符串操作获得详情页的真实网址:

results=page['content']['positionResult']['result']
        ret=[]
        for result in results:
            id=result['positionId']
            ret.append(id)
 urls = ['https://www.lagou.com/jobs/{}.html'.format(i) for i in ret]

最后就是进入详情页的解析并存入数据库就行了。

具体的代码如下 :

 

import requests
import json
import pymongo
from bs4 import BeautifulSoup
from fake_useragent import UserAgent
import time
import pymongo
from config import *   #引入mongodb的配置文件
from requests.exceptions import RequestException  
from mongocache import MongoCache   #这个引入的是我自己写的一个mongodb存储的小程序,下面会写
#最简单的方法是直接使用pymongo进行存储操作,如下面的save_to_mongo
import threading
from queue import Queue


client=pymongo.MongoClient(MONGO_URL,connect=False)
db=client[MONGO_DB]
mongo=MongoCache()

def save_to_mongo(result):    #数据存储方法
    try:
        if db[MONGO_DB].insert(result):
            print('成功存入')
    except Exception:
        print("失败")





class ShiShi:
    def __init__(self):
        _ua=UserAgent()  #模拟随机生成useragent
#cookie是我摘取的我自己的已登录的cookie,这个根据自己进行更改
        self.headers={
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'User-Agent':_ua.random,
            'Accept': '*/*',
            # 'Accept-Language': '',
            'Connection': 'keep-alive',
            'Host': 'www.lagou.com',
            'Referer': 'https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=',
            'Cookie': 'cookie',
            'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
        }
        self.url="https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false"
        self.q = Queue(10)


    #发送带参数的post请求
    def get_page(self,pn,kd):    
        tag = "true" if pn == 1 else "false"
        data = {
            'first': tag,
            'pn': pn,
            'kd':kd
        }
        page=requests.post(self.url,headers=self.headers,data=data).json()
        return page


    #获取页面id,并存入到空列表中
    def get_id(self,page):   
        results=page['content']['positionResult']['result']
        ret=[]
        for result in results:
            id=result['positionId']
            ret.append(id)
        return ret
       

    #对搜索返回的不同页面的id进行整合
    def get_mid(self,pn,kd):
        list = []
        for i in range(1, int(pn) + 1):
            page = self.get_page(i, kd)
            ids = self.get_id(page)

            list.extend(ids)

        return list

     #对id拼接成详情页的url
    def get_real_url(self,ret):
        urls = ['https://www.lagou.com/jobs/{}.html'.format(i) for i in ret]
        return urls

    
    #对详情页进行解析并存入到数据库
    def get_page_detail(self,url):
        try:
            response=requests.get(url,headers=self.headers)
            time.sleep(10)
            if response.status_code==200:
                soup=BeautifulSoup(response.text,'lxml')
                conpany_name=soup.select('#job_company > dt > a > img')
                work_name=soup.select('body > div.position-head > div > div.position-content-l > div > span')
                salary=soup.select('body > div.position-head > div > div.position-content-l > dd > p:nth-of-type(1) > span.salary')
                work_place=soup.select('body > div.position-head > div > div.position-content-l > dd > p:nth-of-type(1) > span:nth-of-type(2)')
                exp_demand=soup.select("body > div.position-head > div > div.position-content-l > dd > p:nth-of-type(1) > span:nth-of-type(3)")
                edu_demand=soup.select('body > div.position-head > div > div.position-content-l > dd > p:nth-of-type(1) > span:nth-of-type(4)')
                job_desc=soup.select('#job_detail > dd.job_bt > div')
                for 公司名称,工作名称,工资待遇,工作地点,经验要求,学历要求,工作描述 in zip(conpany_name,work_name,salary,work_place,exp_demand,edu_demand,job_desc):
                    data={
                        "公司名称" : 公司名称.get('alt'),
                        "工作名称": 工作名称.get_text(),
                        "工资待遇":工资待遇.get_text(),
                        "工作点点":工作地点.get_text(),
                        "经验要求":经验要求.get_text(),
                        "学历要求":学历要求.get_text(),
                        "工作描述":工作描述.get_text(),
                    }
                    mongo.__setitem__(url,data)
                    # write_to_file(data)
            else:
                print("无法连接")

        except RequestException:
            print('出现错误')
    
    #多线程的生产者模式函数
    def produce(self):
        pn = input('请输入你想要爬取多少页:')
        kd = input('你就说你想要搜啥:')
        index=0
        list=self.get_mid(pn,kd)
        urls=self.get_real_url(list)
        while True:
            if index < len(urls):
                self.q.put(urls[index])
                index+=1
    
    #消费者函数
    def consume(self):
        while True:
            url=self.q.get()
            self.get_page_detail(url)
            print('thread is {} content is {}'.format(threading.current_thread(),url))

    def main(self):
        p1 = threading.Thread(target=self.produce, )
        p2 = threading.Thread(target=self.consume, )
        p3 = threading.Thread(target=self.consume, )
        p4 = threading.Thread(target=self.consume, )
        p5 = threading.Thread(target=self.consume, )
        p6 = threading.Thread(target=self.consume, )
        p7 = threading.Thread(target=self.consume, )

        p1.start()
        p2.start()
        p3.start()
        p4.start()
        p5.start()
        p6.start()
        p7.start()

if __name__ == '__main__':
    haha=ShiShi()
    haha.main()

这只是一个简单的聚焦爬虫,其实对于这类含有ajax的网站来说,使用selenium能更加快捷有效的进行爬取。