1. 程式人生 > >python爬蟲爬取拉勾網站內容

python爬蟲爬取拉勾網站內容

       本次主要內容是分享下拉勾網站模擬搜尋以及搜尋內容的爬取,這裡先引入一些用到的庫,由於網站本身的反爬蟲技術和網路原因,這裡使用了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能更加快捷有效的進行爬取。