栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

Python学习笔记之爬虫:利用xpath爬取微博话题下的详细数据

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Python学习笔记之爬虫:利用xpath爬取微博话题下的详细数据

目录

文章目录

前言

一、准备

二、开始爬取

1.引入库

2.主函数main()

3.发送请求函数getHTMLText(url, headers)

4.爬取数据函数getInfo(html,data,headers)

5、储存信息函数saveInfo(data)

6、完整代码

总结


前言

        大二在学校学习了爬虫这门课后,感觉很有趣,实用性也很强,特别是第一次成功爬取到数据时,看着图片自己乖乖下到文件夹中,成就感油然而生。我在实验课上也写过代码爬图片和榜单之类,在结课作业时本来想爬取微博数据做个简单的数据分析,但无奈技艺不精,也就不了了之了。这次在暑假借着数学建模培训的机会,做一个简单的微博话题爬取,为以后比赛中可能要自行寻找数据做准备!(文末有完整代码)


一、准备

开始前,我们需要下载要用到的第三方库,分别是requests库、pandas库、time库、re库、lxml库,以及Google扩展程序Xpath Helper,它能使我们的调试更加方便。

 

我们选择爬取的微博话题是#如何看待明星考编#。

 

微博网址:https://s.weibo.com/weibo?q=%23%E5%A6%82%E4%BD%95%E7%9C%8B%E5%BE%85%E6%98%8E%E6%98%9F%E8%80%83%E7%BC%96%23&page=1

我们爬取的数据是话题页面的各博主ID、博主主页链接、帖子发布时间、转发数、评论数、点赞数、帖子内容、博主粉丝数、博主关注的人数、博主发布微博数,最后将这些数据写入表格中。

结果展示:

 

二、开始爬取

1.引入库

代码如下:

import requests
import pandas as pd
import time
from lxml import etree
import re

2.主函数main()

用户自己的User-Agent与Cookie,需自行在浏览器中找到并添加到此处。

    headers = {
        'User-Agent':'',
        'Cookie':''
    }

设定爬取的页数与URL。

page = 2
basic_url ='https://s.weibo.com/weibo?q=%23%E5%A6%82%E4%BD%95%E7%9C%8B%E5%BE%85%E6%98%8E%E6%98%9F%E8%80%83%E7%BC%96%23&page='

从第一页开始爬取,调用函数爬取数据并保存。

    # 设置一个空列表用于放置话题相关数据
    data = []
    for i in range(page):
        print('正在处理第{}页'.format(i + 1))
        # 构造每一页的url
        url = basic_url + str(i + 1)
        # 调用函数发送请求
        html = getHTMLText(url, headers)
        # 调用函数爬取数据
        getTopicInfo(html, data, headers)
        # 爬完一页睡眠2秒以免被反爬
        time.sleep(2)
    # 调用函数保存数据
    saveTopicInfo(data)
    print('数据保存完毕')

3.发送请求函数getHTMLText(url, headers)

向URL发送请求并获取网页响应内容。

def getHTMLText(url, headers):
    # 定义函数获取网页源代码文本内容
    r = requests.get(url, headers=headers, timeout=30)
    r.raise_for_status()
    r.encoding = r.apparent_encoding
    return r.text

4.爬取数据函数getInfo(html,data,headers)

先对获取的HTML文本进行解析

content=etree.HTML(html)

在找到该页内所有的帖子的xpath列表:

divs = content.xpath('//*[@id="pl_feedlist_index"]/div[4]/div')

在XPath Helper中确认xpath是否正确

 

在对数据进行爬取的过程中,遇到了两个问题:

1、帖子中有无热门和观点标签的xpath不一样

启动调试工具后,选择箭头点击“热门”标签,找到对应Elements中的位置,右键选择复制copy xpath,将该xpath粘贴到扩展程序XPath Helper中;

有热门标签:

无热门标签:

 

有标签博主ID的xpath:(加粗部分为每个帖子的位置,已通过遍历列表得到,红色为差异部分,从div[2]开始是因为div[1]用来储存标签了)

//*[@id="pl_feedlist_index"]/div[4]/div[1]/div[2]/div[1]/div[2]/div[1]/div[2]/a

无标签博主ID的xpath://*[@id="pl_feedlist_index"]/div[4]/div[9]/div/div[1]/div[2]/div[1]/div[2]/a

我们通过判断有无标签来确定xpath:

标签xpath://*[@id="pl_feedlist_index"]/div[4]/div[4]/div[1]/h4/a

if div.xpath('./div[1]/h4'):

2、通过博主链接进入主页后发现request请求到的响应文本与Elements中的代码不一致

通过获取的link链接进入到博主主页获取博主的粉丝数、关注数、发布微博数,分析其源代码发现与requests.get()方法返回代码与浏览器Elements选项卡不一致,在network中XHR下出现info?custom=ID,其访问了一个新网址https://weibo.com/ajax/profile/info?custom=1496814565,该Request URL网址中有我们需要的粉丝数、关注数、发布微博数这些信息。

参考文章:https://blog.csdn.net/yuanzhen1999/article/details/105065803

点击preview查看具体信息,找到粉丝数是"followers_count":32308715,

关注人数:"friends_count":8365

发布微博数:"statuses_count":184870

我们通过拼接网址的方式得到该新网址,并通过正则表达式找到我们所需的粉丝数等信息。

# 开始拼接新网址
# link:https://weibo.com/1496814565?refer_flag=1001030103_
# 利用正则表达式匹配用户ID:1496814565
ID = re.findall('com/+(d*)', link)[0]
# 拼接新网址
url_new = 'https://weibo.com/ajax/profile/info?custom='+ID
link_html = getHTMLText(url_new, headers)
# 新网址源代码中利用正则表达式匹配粉丝数,关注人数,发布微博数
fansnum=re.findall('"followers_count":+(d*)', link_html)[0]
attentionnum=re.findall('"friends_count":+(d*)', link_html)[0]
weibonum=re.findall('"statuses_count":+(d*)', link_html)[0]

5、储存信息函数saveInfo(data)

将爬取到的列表利用pandas存入表格中

def saveInfo(data):
    # 定义函数存储话题信息至本地表格
    # 创建列表分别存储相关数据
    name, link, pbtime, relaysnum, discussnum, goodnum, words, fansnum, attentionnum, weibonum = [], [], [], [], [] ,[], [], [], [], []
    # 将大列表中的对应数据分别存储到相应的列表中
    for d in data:
        name.append(d[0])
        link.append(d[1])
        pbtime.append(d[2])
        relaysnum.append(d[3])
        discussnum.append(d[4])
        goodnum.append(d[5])
        words.append(d[6])
        fansnum.append(d[7])
        attentionnum.append(d[8])
        weibonum.append(d[9])
    # 将上述数据存为字典以便写入本地表格
    dic = {'博主': name, '链接': link, '发布时间': pbtime, '转发数':relaysnum, '讨论数':discussnum, '点赞数':goodnum, '帖子':words, '粉丝数':fansnum ,'关注数':attentionnum, '微博数':weibonum}
    # 使用pandas库保存数据到本地excel表
    TopicData = pd.DataFrame(dic)
    # 储存路径可自行调整
    TopicData.to_excel(r'E:TopicData3.xlsx')

6、完整代码

用户自己的User-Agent与Cookie,需自行在浏览器中找到并添加。

import requests
import pandas as pd
import time
from lxml import etree
import re


def getHTMLText(url, headers):
    # 定义函数获取网页源代码文本内容
    r = requests.get(url, headers=headers, timeout=30)
    r.raise_for_status()
    r.encoding = r.apparent_encoding
    return r.text


def getInfo(html, data, headers):
    # 解析获取的HTML文本
    content=etree.HTML(html)
    # 使用lxml库解析源代码文本
    divs = content.xpath('//*[@id="pl_feedlist_index"]/div[4]/div')
    count = 0
    for div in divs:
        count += 1
        print('开始处理该页第{}个帖子'.format(count))
        #分析网页发现有观点标签和没有观点标签的帖子xpath不一致,故分两种情况
        # 判断有无标签
        if div.xpath('./div[1]/h4'):
            # 博主链接
            link = div.xpath('./div[2]/div[1]/div[2]/div[1]/div[2]/a/@href')
            # 帖子博主ID
            name = div.xpath('./div[2]/div[1]/div[2]/div[1]/div[2]/a/text()')
            # 发布时间
            pbtime = div.xpath('./div[2]/div[1]/div[2]/p[1]/a[1]/text()')
            # 发布帖子
            p=div.xpath('./div[2]/div[1]/div[2]/p[3]/text()')
            words=''
            for i in p:
                i=i.strip()
                if i is not None:
                    words=words+i
            # 转发数,讨论数,点赞数
            relaysnum = div.xpath('./div[2]/div[2]/ul/li[1]/a/text()')
            discussnum = div.xpath('./div[2]/div[2]/ul/li[2]/a/text()')
            goodnum = div.xpath('./div[2]/div[2]/ul/li[3]/a/button/span[2]/text()')
        else:
            # 博主链接
            link = div.xpath('./div/div[1]/div[2]/div[1]/div[2]/a/@href')
            # 帖子博主ID
            name = div.xpath('./div/div[1]/div[2]/div[1]/div[2]/a/text()')
            # 发布时间
            pbtime = div.xpath('./div/div[1]/div[2]/p[1]/a[1]/text()')
            # 发布帖子
            p = div.xpath('./div/div[1]/div[2]/p[3]/text()')
            words = ''
            for i in p:
                i = i.strip()
                if i is not None:
                    words = words + i
            # 转发数,讨论数,点赞数
            relaysnum = div.xpath('./div/div[2]/ul/li[1]/a/text()')
            discussnum = div.xpath('./div/div[2]/ul/li[2]/a/text()')
            goodnum = div.xpath('./div/div[2]/ul/li[3]/a/button/span[2]/text()')
        # 后续处理使爬取数据格式统一
        name = name[0].strip()
        link = 'https:' + link[0].strip()
        # 统一时间格式:'07月07日 20:24'
        pbtime = pbtime[0].strip()[0:12]
        relaysnum = relaysnum[1].strip()
        if relaysnum == '转发':
            relaysnum = '0'
        discussnum = discussnum[0].strip()
        if discussnum == '评论':
            discussnum = '0'
        goodnum=goodnum[0].strip()
        if goodnum == '赞':
            goodnum='0'

        time.sleep(2)
        # 进入到博主主页获取博主的粉丝数,关注数,微博数
        # 分析源代码发现与requests.get()方法返回代码与浏览器Elements选项卡不一致
        # 在network中XHR下出现info?custom=ID,其访问了
        # 一个新网址https://weibo.com/ajax/profile/info?custom=1496814565
        # 该网址有我们所需信息

        # 开始拼接新网址
        # link:https://weibo.com/1496814565?refer_flag=1001030103_
        # 利用正则表达式匹配用户ID:1496814565
        ID = re.findall('com/+(d*)', link)[0]
        # 拼接新网址
        url_new = 'https://weibo.com/ajax/profile/info?custom='+ID
        link_html = getHTMLText(url_new, headers)
        # 新网址源代码中利用正则表达式匹配粉丝数,关注人数,发布微博数
        fansnum=re.findall('"followers_count":+(d*)', link_html)[0]
        attentionnum=re.findall('"friends_count":+(d*)', link_html)[0]
        weibonum=re.findall('"statuses_count":+(d*)', link_html)[0]

        # 将博主ID/博主链接/发布时间/转发数/讨论数/点赞数/帖子/博主粉丝数/博主关注人数/博主发布微博数作为一组列表数据存储到大列表中
        data.append([name, link, pbtime, relaysnum, discussnum, goodnum, words, fansnum, attentionnum, weibonum])



def saveInfo(data):
    # 定义函数存储话题信息至本地表格
    # 创建列表分别存储相关数据
    name, link, pbtime, relaysnum, discussnum, goodnum, words, fansnum, attentionnum, weibonum = [], [], [], [], [] ,[], [], [], [], []
    # 将大列表中的对应数据分别存储到相应的列表中
    for d in data:
        name.append(d[0])
        link.append(d[1])
        pbtime.append(d[2])
        relaysnum.append(d[3])
        discussnum.append(d[4])
        goodnum.append(d[5])
        words.append(d[6])
        fansnum.append(d[7])
        attentionnum.append(d[8])
        weibonum.append(d[9])
    # 将上述数据存为字典以便写入本地表格
    dic = {'博主': name, '链接': link, '发布时间': pbtime, '转发数':relaysnum, '讨论数':discussnum, '点赞数':goodnum, '帖子':words, '粉丝数':fansnum ,'关注数':attentionnum, '微博数':weibonum}
    # 使用pandas库保存数据到本地excel表
    TopicData = pd.DataFrame(dic)
    # 储存路径可自行调整
    TopicData.to_excel(r'E:TopicData3.xlsx')


def main():
    # !!!
    # 用户自己的User-Agent与Cookie,需自行在浏览器中找到并添加到此处
    # !!!
    headers = {
        'User-Agent':'',
        'Cookie':''
    }
    # 设定爬取2页
    page = 2
    # 爬取的url链接
    basic_url ='https://s.weibo.com/weibo?q=%23%E5%A6%82%E4%BD%95%E7%9C%8B%E5%BE%85%E6%98%8E%E6%98%9F%E8%80%83%E7%BC%96%23&page='
    # 设置一个空列表用于放置话题相关数据
    data = []
    for i in range(page):
        print('正在处理第{}页'.format(i + 1))
        # 构造每一页的url
        url = basic_url + str(i + 1)
        # 调用函数发送请求
        html = getHTMLText(url, headers)
        # 调用函数爬取数据
        getInfo(html, data, headers)
        # 爬完一页睡眠2秒以免被反爬
        time.sleep(2)
    # 调用函数保存数据
    saveInfo(data)
    print('数据保存完毕')


main()

总结

以上就是要讲的内容,本文仅仅简单介绍了使用xpath对微博进行爬取,在这个过程中,我复习了xpath、正则表达式等知识(刚学完的差点要还给老师了),也学习了许多其他思路,同时,我也发现,在爬取过程中,有许多的不稳定因素,cookie更新、同一页的帖子中xpath路径也可能有区别、requests.get()方法返回代码与浏览器Elements选项卡不一致等问题,这些问题都是事先没办法预料的,要自己亲自去操作才能知道其中的难点(怪不得老师说爬虫课最难上,这下终于感同身受了),不过最后还是想办法把它们解决了,给自己比个赞,爬虫就到此告一段落了,暑假已悄然过半,接下来继续投入到数学建模备赛中了,希望争取到一个满意的成绩!

转载请注明出处 ,并附有原文链接,若有错误,欢迎指正。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1029770.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号