如何用Python抓取脉脉职言区的评论数据

优采云 发布时间: 2022-05-05 20:15

  如何用Python抓取脉脉职言区的评论数据

  最近对脉脉的“职言”(之前叫匿名讨论区)感兴趣了,发现很多互联网公司的爆料都是从这里开始的,比如近期的互联网界愈演愈烈的“裁员潮”,在这里呈现井喷的趋势。

  

  脉脉“职言”上关于“裁员”的讨论声量趋势分布,与百度指数的搜索量走势高度重合

  由此,笔者决心用Python爬虫去上面抓取网友的讨论数据,以期后续能从中发掘一些有趣的insight,比如大家吐槽的热点(裁员潮、欠薪)、互联网公司的一些雷区(求职面试)以及一些经验(职业发展)...

  笔者发现,在web端是可以登录脉脉的,这就方便了接下来的爬虫数据抓取工作。

  

  脉脉“职言”页面

  笔者在这里是采用搜索的方式定向获取数据,比如,我比较关心职言讨论区涉及“数据分析”的评论,看看大家在讨论“数据分析”的哪些方面的话题。

  先观察下页面结构,笔者发现讨论区的评论是需要不断往下拉才能看到新内容的,所以这里使用了Ajax技术---在网页加载完成后,url虽然不改变但是网页的DOM元素内容却可以动态的变化。

  按下F12,依次点击“Network"-->"XHR",找到下拉加载时产生的请求数据。

  

  发现脉脉“职言”要通过下拉方式才能获得新数据,由此确定它采用了ajax进行加载

  重点关注它的请求URL和请求表单数据。

  

  请求URL和表单数据,这是突破口

  点击Response,发现里面的数据是json格式的,如下图所示:

  

  数据是以json的形式进行呈现

  首先分析该请求的url结构,从中发现规律,方便接下来构造请求链接。在这里,笔者采用Python标准库urllib中的parse库,用来解析和构造链接。

  <p style="line-height: 1.5em;">from urllib.parse import urlparse,parse_qs,urlencode

url_name = urlparse(

   'https://maimai.cn/search/gossips?query=%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90&limit=20&offset=20&searchTokens=%5B%22%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%22%5D&highlight=true&sortby=&jsononly=1')

url_name</p>

  ParseResult(scheme='https', netloc='', path='/search/gossips', params='',query='query=%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90&limit=20&offset=20&searchTokens=%5B%22%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%22%5D&highlight=true&sortby=&jsononly=1', fragment='')

  依次得到协议类型、域名、路径、参数、请求和fragment。

  将上面的query再进行解析,得到请求参数。

  <p style="line-height: 1.5em;">parse_qs('query=%E8%A3%81%E5%91%98&limit=20&offset=20&searchTokens=%5B%22%E8%A3%81%E5%91%98%22%5D&highlight=true&sortby=&jsononly=1')</p>

  {'query': ['裁员'], 'limit': ['20'], 'offset': ['20'], 'searchTokens': ['["裁员"]'], 'highlight': ['true'], 'jsononly': ['1']}

  对于解析出来的结果,重点关注query、offset和searchTokens。其中,offset是偏移量,以20为单位进行增量,而query和searchTokens就是一回事,构造链接的时候写成一样的表达即可。

  编写如下的链接构造函数。

  <p style="line-height: 1.5em;">def key_word_search_url(keyword,offset):    

   data = {'query': keyword,

          'limit': 20,

          'offset': offset,  

          'searchTokens': keyword,

          'highlight': 'true',            

          'jsononly': '1'}    

   search_url = 'https://maimai.cn/search/gossips?' + urlencode(data)          

   return search_url</p>

  试试效果如何,以“社交媒体”为例,offset为20进行测试

  <p style="line-height: 1.5em;">key_word_search_url('社交媒体',20)</p>

  '%E7%A4%BE%E4%BA%A4%E5%AA%92%E4%BD%93&limit=20&offset=20&searchTokens=%E7%A4%BE%E4%BA%A4%E5%AA%92%E4%BD%93&highlight=true&jsononly=1'

  将构造的链接放到浏览器中,看看能不能请求到数据。

  

  json格式的数据,其实这种形式的数据是爬虫最喜欢的!

  看来构造出来的请求链接是OK的!

  好了,可以正式开始爬虫编写了!

  第一步:载入必要的库,以及采用post方式进行登录。

  <p style="line-height: 1.5em;">import requests

import re

import lxml.etree

import lxml.html

from urllib.parse import urlparse,parse_qs,urlencode

from tqdm import tqdm

from tkinter import _flatten

import pandas as pd

from fake_useragent import UserAgent

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor

from requests_futures.sessions import FuturesSession

from requests import Session

import time

import os

import random

ua = UserAgent()  #随机生成用户代理

requests_session = FuturesSession(executor = ProcessPoolExecutor(max_workers=10),session=Session())

headers = {'user-agent':ua.random ,

          'path':'/search/gossips?query=%E5%8F%A3%E7%A2%91&limit=20&offset=20&searchTokens=%5B%22%E5%8F%A3%E7%A2%91%22%5D&highlight=true&sortby=&jsononly=1',

          'authority':'脉脉-成就职业梦想',

          'referer':'https://maimai.cn/web/search_center?type=gossip&query=%E5%8F%A3%E7%A2%91&highlight=true',

          'cookie':'''guid=GxIaBBsfEwQbEx4EGxgeVhkaGBMZHhpWGhoeBB0dHxgEGQQaGwVYT1ldRVhoe3sKGhoeBBwdHRwEGRwEGwVPWEVpChwZBB0ZHwVDWEtMS3kKHBgEExkYGQQaBBkcBU9HRVhCaQoDRUFJT20KT0FDRgoGZmd+YmECChwZBB0ZHwVeQ2FIT31PRlpaawoDHhx9ZX0KERoEGhsKfmQKWV1FTkRDfQIKGgQfBUtGRkNQRWc=; sessionid=yolyiy13px6c3wk1lc07c0tlmmmx2f4g; _buuid=558e1d44-6e93-4c65-8220-ecd9a4f050f5; seid=s1547559716083; token="AInmyu9niNxiQtnPCJUJ0Z68TJNWVCIqNEk0FkCcf/I604SlzRt13U0Bc6nfEokW8CKuzcDfAvoCmBm7+jVysA=="; uid="RKwErF8zWf7OH6XWrEWK4fAirs3A3wL6ApgZu/o1crA="; session=eyJ1IjoiMzA3ODMxOTIiLCJzZWNyZXQiOiJyLVFPZTFhSFd2UE1fVmhhMHFZNjFWVE0iLCJfZXhwaXJlIjoxNTQ3NjQ2MTQ2OTQ0LCJfbWF4QWdlIjo4NjQwMDAwMH0=; session.sig=wrNrB1mK9WOBUNgU2ZFv7KMlGO0'''

}  

data = {'u':'30783192',

'channel':'www',

'version':'4.0.0',

'_csrf':'semzdd8v-7gvL_7e0fLTVhsFMvglLykXUnuE',

'access_token':'1.c8169081785b6fd48f6a960f6719cfb8',

'uid':"RKwErF8zWf7OH6XWrEWK4fAirs3A3wL6ApgZu/o1crA=",

'token':"AInmyu9niNxiQtnPCJUJ0Z68TJNWVCIqNEk0FkCcf/I604SlzRt13U0Bc6nfEokW8CKuzcDfAvoCmBm7+jVysA=="}

#response = requests.post('https://www.huxiu.com/v2_action/article_list', headers=headers,data = data)

response =  requests_session.post('脉脉-成就职业梦想, headers=headers,data = data)

# 通过get请求返回的文本值

#print(response.result().text)</p>

  第二步:使用代理IP进行数据爬取,防止爬虫被封。

  <p style="line-height: 1.5em;">api_url = 'http://dynamic.goubanjia.com/dynamic/get/a93a315bcfae9120aee86832d3adca44.html?sep=3&random=true'

proxy_host = None

def update_proxy():

   import urllib

   global proxy_host

   print('请求代理...')

   proxy_host  = urllib.request.urlopen(api_url).read().decode('utf-8').strip('\n')

   print('取得代理IP:',proxy_host)</p>

  第三步:编写解析函数,即获得页面的json数据。

  <p style="line-height: 1.5em;">def parse_page(keyword,offset):

   response_list = []

   update_proxy()

   proxies = {'http':proxy_host}  

       

   for i in range(0,offset,20):

       response = requests_session.get(key_word_search_url(keyword,offset),

                                       headers=headers,

                                       proxies=proxies)

       time.sleep(random.randint(2,6)) #在2秒~6秒钟随意切换数值,降低爬取频率,防止被封杀

       # 通过get请求返回的文本值

       response_list.append(response.result())

       

   data = _flatten([i.json()['data']['gossips'] for i in response_list])

   print(len(data))

   return data   </p>

  第四步:将前面的函数整合到一起,提取json数据中重要的字段。

  其中涉及:

  <p style="line-height: 1.5em;">def main(keyword,offset):

   

   name,text,total_cnt,likes,unlikes,crtime,id,is_freeze,search_order,encode_id= [],[],[],[],[],[],[],[],[],[]

   for i in tqdm(parse_page(keyword,offset)):    

       name.append(i['gossip']['username'])         #昵称

       text.append(i['gossip']['text'])             #文本

       total_cnt.append(i['gossip']['total_cnt'])   #评论数

       likes.append(i['gossip']['likes'])           #喜欢数

       unlikes.append( i['gossip']['unlikes'])      #讨厌数

       crtime.append(i['gossip']['crtime'])        #创建时间

       id.append(i['gossip']['id'])                #匿言ID

       is_freeze.append(i['gossip']['is_freeze'])         #匿言is_freeze

       search_order.append(i['gossip']['search_order'])     #匿言检索顺序

       encode_id.append(i['gossip']['encode_id'])       #匿言帖子编码

   

   data = {'name':name,'text':text,'total_cnt':total_cnt,'likes':likes,'unlikes':unlikes,'crtime':crtime,'id':id,'is_freeze':is_freeze,'search_order':search_order,'encode_id':encode_id}    

   data_house = pd.DataFrame(data,columns=['name','text','total_cnt','likes','unlikes','crtime','id','is_freeze','search_order','encode_id'])

   data_house = data_house.drop_duplicates("id")

   data_house = data_house.sort_values(by='total_cnt',ascending=False)

   data_house.to_csv('{}.csv'.format(keyword))

   return data_house    </p>

  函数编写完成后,先提取部分数据试试。

  <p style="line-height: 1.5em;">data_list = main('数据分析',60)</p>

  

  

  工工整整的表格数据,做文本挖掘很适合!

  看来效果不错!

  有了这些数据以后,你可以做:

  之前有过类似的分析,详情请参看:

  苏格兰折耳喵:

  苏格兰折耳喵:

  苏格兰折耳喵:

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线