雪球网股票用户评论爬虫

一、什么是爬虫?

网络爬虫,其实叫作网络数据采集更容易理解。
就是通过编程向网络服务器请求数据(HTML表单),然后解析HTML,提取出自己想要的数据。
归纳为四大步:

1.根据url获取HTML数据
2.解析HTML,获取目标信息
3.存储数据
4.重复第一步

二、HTML

什么是HTML?
超文本标记语言(英语:HyperTextMarkupLanguage,简称:HTML)是一种用于创建网页的标记语言,里面嵌入了文本、图像等数据,可以被浏览器读取,并渲染成我们看到的网页样子。
所以我们才会从先爬取HTML,再 解析数据,因为数据藏在HTML里
比如这就是一个简单的html程序

<!DOCTYPE html>
<html>
  <head>
    <title>This is a title</title>
  </head>
  <body>
    <p>Hello world!</p>
  </body>
</html>

三、爬虫基本原理

在编写python爬虫程序时,只需要做以下两件事:
①发送GET请求(模拟计算机对服务器发起Request请求),获取HTML
②解析HTML,获取数据
这两件事,python都有相应的库帮你去做,你只需要知道如何去用它们就可以了。

四、爬虫三大库

1.Request库

作用是请求网站获取网页数据

import requests
res = requests.get('http://www.baidu.com')
print(res)   # 返回200则请求网址成功,404或者400则失败
print(res.text)

显示的结果和F 12的一样

有时爬虫需要加入请求头来伪装成浏览器,以便更好地抓取数据。
在F 12里的network里headers中找到User-Agent进行复制
在这里插入图片描述

import requests
headers = {
       'User-Agent':' Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko))Chrome/87.0.4280.66 Safari/537.36'
}

res = requests.get('http://www.baidu.com')
print(res)   # 返回200则请求网址成功,404或者400则失败
print(res.text)

Requsets 库不仅有get()方法,还有post()等方法,用来提交表单来爬取需要登陆才能获取数据的网络。
如果遇到抛出异常,修改后爬虫程序还需要再重新运行,效率很低。这时可以使用try来避免异常

try:
    print(res.text)
except ConnectionError    #出现except后面的错误后执行下面聚聚
    print('拒绝连接')
2. BeautifulSoup库

通过BeautifulSoup库可以轻松解析Request库请求的页面,并把网页的源代码解析成Soup文档,以便过滤提取数据

import requests
from bs4 import BeautifulSoup
headers = {
       'User-Agent':' Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko))Chrome/87.0.4280.66 Safari/537.36'
}
res = requests.get('http://www.baidu.com')
soup = BeautifulSoup(res.text,'html.parser')   # 对返回的结果进行解析
print (soup.prettify())

其实输出的内容和request的一样,但它按照标准缩进格式的结构输出,为后续数据过滤提取做好准备。

解析Soup文档可以使用find()、find_all()和selector()定位需要的元素。
1.find_all()

soup.find_all( ‘div’,“item” ) ## 查找div标签,class=“item”
soup.find_all( ‘div’,class=“item” )

2.find()
与上者类似,只是find_all()返回的是文档中符合条件的所有tag,是一个集合(class ’ bs4.element.ReaultSet ’ )
而find()是返回一个Tag(class ’ bs4.element.Tag ’ )

五、正则表达式

正则表达式是一个特殊的符号系列,用于检查一个字符串是否与某种模式匹配。
用的是python中的re模块

1. 正则表达式常用符号

在这里插入图片描述
在这里插入图片描述

2.re模块及其方法

1.search()
用于匹配并提取第一个符合规律的内容,返回一个正则表达式对象。

re.match ( pattern , string , flags=0 )

其中:
pattern为匹配的正则表达式
string为匹配的字符串
flag为标志为,用于控制正则表达式,如是否区别大小写等

下面附上代码

#encoding: utf-8

import requests
import re
import json
import csv
import time
import datetime

# cookie替换成从自己的浏览器获取到的cookie,需要登录后再获取否则无法爬取超过5页数据
cookie = '你自己的cookie'
headers = {
    'Host':"xueqiu.com",
    'Referer': 'https://xueqiu.com/',
    'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.87 Safari/537.36",
    'Accept':"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
    'Connection':'keep-alive',
    'Cookie': cookie
}

# 初始化数据
page = 1
userid = 9219380043   # 这里填写你要爬取的用户UID
type = 0
url = 'https://xueqiu.com/v4/statuses/user_timeline.json'+'?page='+str(page)+'&user_id='+str(userid)+'&type='+str(type)
response = requests.get(url, headers = headers)
text = response.text
dict_text = json.loads(text)
# 获取maxPage
maxPage = dict_text['maxPage']
userName = dict_text['statuses'][0]['user']['screen_name']
csv_headers = ['id','user_id','source','title','created_at','retweet_count','reply_count','fav_count','truncated','commentid','retweet_status_id','symbol_id','description','type','source_link','edited_at','mark', 'reward', 'liked', 'quote_cards', 'rqtype', 'paid_mention', 'is_answer', 'donate_count', 'text', 'is_no_archive', 'topic_desc', 'firstImg', 'offer', 'topic_symbol', 'longTextForIOS', 'cover_pic', 'promotion_url', 'target', 'topic_pic_headOrPad', 'retweeted_status', 'like_count', 'commentId', 'status_industry', 'meta_keywords', 'is_column', 'timeBefore', 'is_bonus', 'favorited', 'recommend_cards', 'is_original_declare', 'topic_pic_thumbnail', 'score', 'is_refused', 'reward_amount', 'notice_tag', 'promotion_pic', 'excellent_comments', 'talk_count', 'show_cover_pic', 'expend', 'is_private', 'pic_sizes', 'new_card', 'rqid', 'fragment', 'topic_pic', 'rawTitle', 'stockCorrelation', 'promotion_id', 'canEdit', 'blocking', 'pic', 'blocked', 'topic_title', 'reward_user_count', 'cover_pic_size', 'reward_count', 'forbidden_retweet', 'card', 'topic_pic_thumbnail_small', 'view_count', 'reply_user_count', 'is_ss_multi_pic', 'tagStr', 'common_emotion', 'answers', 'weixin_retweet_count', 'tags', 'favorited_created_at', 'controversial', 'donate_snowcoin', 'mp_not_show_status', 'mark_desc', 'user', 'reply_user_images', 'tagsForWeb', 'order_id', 'current_stock_price', 'forbidden_comment']
last_index = 0
statuses_formatted = []
csv_headers_statuses_formatted = ['发布时间','转发数','评论数','收藏数','点赞数','动态内容']
for page in range(1,maxPage+1):
    url = 'https://xueqiu.com/v4/statuses/user_timeline.json'+'?page='+str(page)+'&user_id='+str(userid)+'&type='+str(type)
    response = requests.get(url, headers = headers)
    text = response.text
    dict_text = json.loads(text)
    print('正在爬取第'+str(page)+'页...')
    if page == 1:
        statuses = dict_text['statuses']
    else:
        statuses = statuses + dict_text['statuses']
    print('当前爬取的数据量:'+str(len(statuses))+'条')
    # 格式化created_time, text
    for index in range(last_index,len(statuses)):
        before_formatting = dict_text['statuses'][index-last_index]['created_at']
        if before_formatting:
            before_formatting = datetime.datetime.fromtimestamp(int(before_formatting) / 1000).strftime('%Y-%m-%d %H:%M:%S')
        dict_text['statuses'][index-last_index]['created_at'] = before_formatting
        temp_text = dict_text['statuses'][index-last_index]['text']
        if temp_text:
            temp_text = re.compile(r'<[^>]+>',re.S).sub('', temp_text)
            print(temp_text)
        dict_text['statuses'][index-last_index]['text'] = temp_text
        if len(dict_text['statuses'][index-last_index]['text']) > 0:
            statuses_formatted.append(dict(发布时间=dict_text['statuses'][index-last_index]['created_at'],转发数=dict_text['statuses'][index-last_index]['retweet_count'],评论数=dict_text['statuses'][index-last_index]['reply_count'],收藏数=dict_text['statuses'][index-last_index]['fav_count'],点赞数=dict_text['statuses'][index-last_index]['like_count'],动态内容=dict_text['statuses'][index-last_index]['text']))
    last_index = len(statuses)
    # 防止反爬虫机制,每爬取100条休息15秒
    if page%100 == 99:
        time.sleep(15)
    # with open(str(userName)+'.csv', 'w', encoding='utf-8', newline='') as fp:
    #     writer = csv.DictWriter(fp,csv_headers)
    #     writer.writeheader()
    #    # writer.writerows(statuses)
    with open(str(userName)+'_Formatted.csv', 'w', encoding='utf-8', newline='') as fp:
        writer = csv.DictWriter(fp,csv_headers_statuses_formatted)
        writer.writeheader()
        writer.writerows(statuses_formatted)

让我们看看结果
在这里插入图片描述
在这里插入图片描述

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值