python在爬取微信公众号的文章时,你可能踩过的坑我都帮你踩了(上)

最近因为公司的需要获取一些微信公众号的文章内容,阅读量还有发布的时间等出来对比分析,开始以为挺简单,因为网上有大量的案例,但是真正做起来都是问题。

    • 一、登录微信公众平台获取cookies
    • 二、爬取一个公众号中的文章名和链接

首先整理一下思路:1.要想获取公众号的文章,首先需要在微信公众平台有个账号,2.找到搜索公众号的位置(这个位置在:素材管理-新建图文消息-超链接),3.抓包工具(我用的是fiddler)获取请求headers的必要参数,通过这步我们就可以获取公众号的文章链接,4.根据链接获取文章里面的浏览量。

一、登录微信公众平台获取cookies

在后面写爬虫中,需要获取登录的用户的cookies才能进行文章的爬取,所以这里我们需要将cookies获取保存到本地,我测试了一下,cookies的有效时间在两个小时以内,由于学过selenium自动登录,所以我用了selenium做了自动登录保存cookies到本地,自动登录的代码后面还是需要手机扫码的(因为二维码没法破解),自动登录代码如下,比较简单:
下面展示一些 内联代码片

from selenium import webdriver
import time
import json
def weiXin_login():
    # 定义一个空的字典,存放cookies内容
    post = {}
    driver = webdriver.Chrome()
    driver.get('https://mp.weixin.qq.com/')  # 打开微信后台
    time.sleep(3)
    print("正在输入微信公众号登录账号和密码......")
    driver.find_element_by_xpath(".//*[@id='header']/div[2]/div/div/div[2]/a").click()
    driver.find_element_by_xpath(".//*[@id='header']/div[2]/div/div/div[1]/form/div[1]/div[1]/div/span/input").clear()
    driver.find_element_by_xpath(
        ".//*[@id='header']/div[2]/div/div/div[1]/form/div[1]/div[1]/div/span/input").send_keys(user)
    driver.find_element_by_xpath(".//*[@id='header']/div[2]/div/div/div[1]/form/div[1]/div[2]/div/span/input").clear()
    driver.find_element_by_xpath(
        ".//*[@id='header']/div[2]/div/div/div[1]/form/div[1]/div[2]/div/span/input").send_keys(password)
    time.sleep(10)
    driver.find_element_by_xpath(".//*[@id='header']/div[2]/div/div/div[1]/form/div[4]/a").click()
    time.sleep(20)

    print("登录成功")
    driver.get('https://mp.weixin.qq.com/')  # 重新进后台,获取cookie信息
    cookie_items = driver.get_cookies()  # 获取cookies信息

    # 获取到的cookies是列表形式,将cookies转成json形式并存入本地名为cookie的文本中
    for cookie_item in cookie_items:
        post[cookie_item['name']] = cookie_item['value']
    cookie_str = json.dumps(post)
    with open('cookie.txt', 'w+', encoding='utf-8') as f:
        f.write(cookie_str)
    print("cookies信息已保存到本地")

通过这一步我们就可以将登录的用户cookie保存到本地,给接下来公众号爬取做准备。

二、爬取一个公众号中的文章名和链接

1.首先利用fiddler抓包工具,搜索一个公众号:腾讯视频,我们就可以在fiddler中获取到返回的json数据,这里只说爬一个公众号,其实如果爬多个公众号也是一样的过程,只不过我们取第一个公众号而已。
python在爬取微信公众号的文章时,你可能踩过的坑我都帮你踩了(上)_第1张图片
python在爬取微信公众号的文章时,你可能踩过的坑我都帮你踩了(上)_第2张图片
2.fiddler已经帮我们抓到json数据了,接下来我们就通过代码获取json,首先就是拼接请求头headers,请求头参数很多,但其实用到的不多,我刚开始把fiddler得到的请求头都写进去,但是后面做ip代理和UA池的时候发现多了会出现问题,所以headers这里用到Host和User-Agent就可以了。
python在爬取微信公众号的文章时,你可能踩过的坑我都帮你踩了(上)_第3张图片
公众号的路由:https://mp.weixin.qq.com/
想要搜索一个公众号,我们就得知道两个重要的参数,一个是token 和query,其他的参数都可以在fiddler里面复制下来。token是用户登录后的一个唯一标识符,在你登录后会显示,query是你搜索的公众号名。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200721183840467.pngpython在爬取微信公众号的文章时,你可能踩过的坑我都帮你踩了(上)_第4张图片
在这里插入图片描述

def get_content(query):
    # title_header=["发布时间","文章标题","阅读量","文章链接"]
    url="https://mp.weixin.qq.com/"
    headers={
        "Host":"mp.weixin.qq.com",
        "User-Agent":user_agent.random +"(KHTML, like Gecko) Version/4.0 Chrome/78.0.3904.62 XWEB/2469 MMWEBSDK/200601 Mobile Safari/537.36 MMWEBID/3809 MicroMessenger/7.0.16.1680(0x27001033) Process/toolsmp WeChat/arm64 NetType/WIFI Language/zh_CN ABI/arm64"
    }
    with open("cookies.txt","r",encoding="utf-8")as f:
        cookies=f.read()
        cookies=json.loads(cookies)

    response=requests.get(url=url,headers=headers,cookies=cookies,proxies=ranDom_ip()[0],verify=False)
    token=re.findall(r'token=(\d+)?',str(response.url))[0] #获取登录的token信息
    search_url='https://mp.weixin.qq.com/cgi-bin/searchbiz?' #公众号超链接搜索路由
    search_data={
        "action":"search_biz",
        "ajax":"1",
        "begin":"0",
        "random_num": random.random(),
        "count":"5",
        "f":"json",
        "lang":"zh_CN",
        "query":query,
        "token":token,
    } #搜索携带的参数
    search_response=requests.get(search_url,headers=headers,cookies=cookies,proxies=ranDom_ip()[0],params=search_data,verify=False)
    lists=search_response.json().get('list')[0]#获取第一个搜索的公众号
    fakeid=lists['fakeid'] #下面文章中需要的参数

通过上面的代码我们就可以获取到用户登录的token,第一个公众号的fakeid。

要获取一个公众号下面的文章,我们有两个必带的参数,token,fakeid,
文章的路由:https://mp.weixin.qq.com/cgi-bin/appmsg?
我们先通过fiddler点击一个公众号,再去fiddler找相应的路由看参数的变化,主要是看是否获取到公众号下面的文章。
python在爬取微信公众号的文章时,你可能踩过的坑我都帮你踩了(上)_第5张图片
通过分析fiddler是可以获取到json数据,我们可以看到这里需要携带的参数挺多的,那我们在get请求的时候可以拼接带上,然后通过get请求获取腾讯视频里面文章的json数据,接着上面的代码,再写一个get请求

appmsg_url='https://mp.weixin.qq.com/cgi-bin/appmsg?' #文章的路由
    appmsg_data={
        "action":"list_ex",
        "begin":"0",
        "count":"5",
        "fakeid":fakeid,
        "type":"9",
        "random_num":random.random(),
        "query":"",
        "token":token,
        "lang":"zh_CN",
        "f":"json",
        "ajax":"1"

    }
    appmsg_list=requests.get(appmsg_url,cookies=cookies,headers=headers,proxies=ranDom_ip()[0],params=appmsg_data,verify=False)

从上面的参数我们不难看出,我们现在获取到的只是第一页的文章而已,通过调参数里面的数值,我们可以得到想要页数的文章数据:
python在爬取微信公众号的文章时,你可能踩过的坑我都帮你踩了(上)_第6张图片
到这里的话,通过get下来的json数据,我们就可以将文章的标题和链接获取到,这里如果细节一点的话,还可以获取到发布的时间,这样基本数据就可以ok了,但是这还不能满足需求,因为微信这个反爬特别严重,我亲自测了一下,文章爬取500篇左右就会被识别到禁止获取数据了,所以需要加入UA池和IP代理池,要是想获取到每一篇文章的阅读量的话,我们还需要点击没一篇文章的链接,然后通过post请求获取文章阅读量。
下一篇文章我将会说明怎么获取每篇文章的阅读量和绕过微信反爬
下面是爬取某个公众号文章名、发布时间、链接的完整代码,有兴趣的小伙伴可以看看:

def get_content(query):
    # title_header=["发布时间","文章标题","阅读量","文章链接"]
    url="https://mp.weixin.qq.com/"
    headers={
        "Host":"mp.weixin.qq.com",
        "User-Agent":user_agent.random +"(KHTML, like Gecko) Version/4.0 Chrome/78.0.3904.62 XWEB/2469 MMWEBSDK/200601 Mobile Safari/537.36 MMWEBID/3809 MicroMessenger/7.0.16.1680(0x27001033) Process/toolsmp WeChat/arm64 NetType/WIFI Language/zh_CN ABI/arm64"
    }
    with open("cookies.txt","r",encoding="utf-8")as f:
        cookies=f.read()
        cookies=json.loads(cookies)

    response=requests.get(url=url,headers=headers,cookies=cookies,proxies=ranDom_ip()[0],verify=False)
    token=re.findall(r'token=(\d+)?',str(response.url))[0] #获取登录的token信息
    search_url='https://mp.weixin.qq.com/cgi-bin/searchbiz?' #公众号超链接搜索路由
    search_data={
        "action":"search_biz",
        "ajax":"1",
        "begin":"0",
        "random_num": random.random(),
        "count":"5",
        "f":"json",
        "lang":"zh_CN",
        "query":query,
        "token":token,
    } #搜索携带的参数
    search_response=requests.get(search_url,headers=headers,cookies=cookies,proxies=ranDom_ip()[0],params=search_data,verify=False)
    lists=search_response.json().get('list')[0]#获取第一个搜索的公众号
    fakeid=lists['fakeid'] #下面文章中需要的参数

    appmsg_url='https://mp.weixin.qq.com/cgi-bin/appmsg?' #文章的路由
    appmsg_data={
        "action":"list_ex",
        "begin":"0",
        "count":"5",
        "fakeid":fakeid,
        "type":"9",
        "random_num":random.random(),
        "query":"",
        "token":token,
        "lang":"zh_CN",
        "f":"json",
        "ajax":"1"

    }
    appmsg_list=requests.get(appmsg_url,cookies=cookies,headers=headers,proxies=ranDom_ip()[0],params=appmsg_data,verify=False)
    max_page=appmsg_list.json()['app_msg_cnt'] #获取文章的总页数
    min=int(int(max_page)/5)
    a=1
    begin=0
    with open("./App_sheet/{}公众号文章.csv".format(input_content), "a+", encoding="utf-8", newline="")as f:
        write = csv.writer(f)
        # write.writerow(title_header)
        while min+1>0:
            data={
        "action": "list_ex",
        "begin": "{}".format(str(begin)),
        "count": "5",
        "fakeid": fakeid,
        "random_num": random.random(),
        "type": "9",
        "query": "",
        "token": token,
        "lang": "zh_CN",
        "f": "json",
        "ajax": "1"
    }
            headers={
                 "Host":"mp.weixin.qq.com",
                  "User-Agent":user_agent.random +"(KHTML, like Gecko) Version/4.0 Chrome/78.0.3904.62 XWEB/2469 MMWEBSDK/200601 Mobile Safari/537.36 MMWEBID/3809 MicroMessenger/7.0.16.1680(0x27001033) Process/toolsmp WeChat/arm64 NetType/WIFI Language/zh_CN ABI/arm64"
           }
            ip_num=ranDom_ip()[0]
            print("正在获取第%s页文章数据"%a)
            wenhang_title=requests.get(appmsg_url,cookies=cookies,headers=headers,proxies=ip_num,params=data,verify=False)
            sleep(0.5)
            reponse=wenhang_title.json()
            for dic in reponse['app_msg_list']:
                title=dic['title']
                link=dic['link']
                readnNum=get_readNum(link,headers['User-Agent'],ip_num)
                create_time=time.localtime(dic['create_time'])
                create_time=time.strftime("%Y-%m-%d",create_time)
                write.writerow([create_time,title.strip(),readnNum,link])

            begin+=5
            min-=1
            a+=1
            sleep(0.1)

if __name__ == '__main__':
    # Wchat_login()
    input_content = input("请输入要搜索的公众号:")
    content_list = [input_content]
    for query in content_list:
        get_content(query)
   

你可能感兴趣的:(爬虫,app爬虫,python)