一、起因
最近几天陈情令大火,而#肖战#王一博等人也成为众人所熟知的对象,所以我想用Scrapy爬取演员的微博信息来分析下演员信息
二、 目标
本次爬取的目标是X玖少年团肖战DAYTOY的公开基本信息,如用户昵称、头像、用户的关注、粉丝列表以及发布的微博等,这些信息抓取之后保存至Mysql,并绘制出图表
三、准备工作
请确保代理池、Cookies池已经实现并可以正常运行,安装Scrapy、PyMysql库。这里我新注册了四个微博账号,防止爬虫被封
四、爬取思路
其实使用Requests+BeautifulSoup可以很灵活的对微博进行爬取,但因为是单线程,并发效率不高,爬取的速度很慢,所以使用Scrapy+XPath可以很高效的爬取
首先我们要实现对X玖少年团肖战DAYTOY的爬取。这里采用的爬取方式是,以用户的URL为起始点,爬取他发表的微博的内容、时间、转发数、评论数、点赞数,并通过Item管道输出至Mysql数据库,然后将数据绘制成图表
五、爬取分析
新浪微博一共有三个站点:weibo.cn,m.weibo.cn,weibo.com,相对应的爬取难度也依次变高,所以为了降低爬取难度,这里我们选取的爬取站点是:https://weibo.cn,此站点是微博移动端的站点。打开该站点会跳转到登录页面,这是因为主页做了登录限制。不过我们可以用cookie绕过登录限制,直接打开某个用户详情页面,此处打开X玖少年团肖战DAYTOY的微博,链接为:https://weibo.cn/u/1792951112,即可进入其个人详情页面,如下图所示。
以下是我们需要爬取的信息
六、创建爬虫
scrapy startproject weibo
scrapy genspider weibocn weibo.cn
七、创建Items
class WeiboItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
text_fanart = scrapy.Field() #原创内容
text_transfrom = scrapy.Field() #转发内容
comment = scrapy.Field() #评论数
like = scrapy.Field() #点赞数
transmit = scrapy.Field() #转发数
time = scrapy.Field() #发表时间
_from = scrapy.Field() #来自的客户端
八、编写spider
class WeibocnSpider(scrapy.Spider):
name = 'weibocn'
allowed_domains = ['weibo.cn']
url = 'https://weibo.cn/u/1792951112?page={page}'
# start_urls = ['https://weibo.cn/u/1792951112']
def transform(self, cookies):
cookie_dict = {}
cookies = cookies.replace(' ', '')
list = cookies.split(';')
for i in list:
keys = i.split('=')[0]
values = i.split('=')[1]
cookie_dict[keys] = values
return cookie_dict
#Override start_requests()
#此方法相当于 requests.get()方法
def start_requests(self):
for page in range(1,65):
yield scrapy.Request(url=self.url.format(page=page),callback=self.parse)
# 此方法中的response相当于response = requests.get()
def parse(self, response):
# print(response.text)
item = WeiboItem()
for p in response.xpath("//div[@class='c'and @id]"):
try:
text_transfrom = "".join(p.xpath("./div/text()").re(r'[\u4e00-\u9fa5]'))
text_fanart = "".join(p.xpath("./div/span[@class='ctt']/text()").extract())
item['text_fanart'] = text_fanart
item['text_transfrom'] = text_transfrom
item['like'] = "".join(p.xpath("./div/a").re(r'赞\[[0-9]*?\]')).replace('赞[','').replace(']','')
item['transmit'] = "".join(p.xpath("./div/a").re(r'转发\[[0-9]*?\]')).replace('转发[', '').replace(']', '')
item['comment'] = "".join(p.xpath("./div/a").re(r'评论\[[0-9]*?\]')).replace('评论[', '').replace(']', '')
time_from = "".join(p.xpath("./div/span[@class='ct']/text()").extract()).split("\xa0来自")
item['time'] = time_from[0]
item['_from'] = time_from[1]
yield item
except Exception as e:
print(e)
continue
九、数据清洗
有些微博的时间可能不是标准的时间,比如它可能显示为刚刚、几分钟前、几小时前、昨天等。这里我们需要统一转化这些时间,实现一个方法,代码如下所示:
def clear_date(self,publish_time):
if "刚刚" in publish_time:
publish_time = datetime.now().strftime('%Y-%m-%d %H:%M')
elif "分钟" in publish_time:
minute = publish_time[:publish_time.find("分钟")]
minute = timedelta(minutes=int(minute))
publish_time = (
datetime.now() - minute).strftime(
"%Y-%m-%d %H:%M")
elif "今天" in publish_time:
today = datetime.now().strftime("%Y-%m-%d")
time = publish_time.replace('今天', '')
publish_time = today + " " + time
elif "月" in publish_time:
year = datetime.now().strftime("%Y")
publish_time = str(publish_time)
publish_time = year + "-" + publish_time.replace('月', '-').replace('日', '')
else:
publish_time = publish_time[:16]
return publish_time
十、编写pipelines
class WeiboPipeline(object):
def __init__(self):
#创建连接
self.conn = pymysql.connect('localhost','root','root','sina')
#创建游标
self.cursor = self.conn.cursor()
#管道处理,将数据存入mysql
def process_item(self, item, spider):
sql = "INSERT INTO weibocn(text_fanart,text_transfrom,comment,`like`,transmit,`time`,`from`) VALUES (%s,%s,%s,%s,%s,%s,%s)"
print('==================================')
self.cursor.execute(sql,(item['text_fanart'],item['text_transfrom'],item['comment'],item['like'],item['transmit'],item['time'],item['_from']))
self.conn.commit()
return item
#关闭sqldb
def close_spider(self,spider):
self.cursor.close()
self.conn.close()
十一、开启管道
进入settings.py文件中启用管道
ITEM_PIPELINES = {
'weibo.pipelines.WeiboPipeline': 300
}
十二、运行scrapy
scrapy crawl weibocn
运行结果如下图:
十三、数据库插入报错InternalError: (pymysql.err.InternalError) (1366, "Incorrect string value: '\\xE6\\xAD
解决方法:https://blog.csdn.net/sinat_41721615/article/details/94979429
十四、绘制图表
这里使用的matplotlib库做出的图,没有审美天赋,所以做出来的图比较丑
import csv
import matplotlib.pyplot as plt
import numpy as np
file = open('weibocn.csv','r')
reader = csv.reader(file)
comment_list = []
like_list = []
transmit_list = []
time_list = []
for comment,like,transmit,time in reader:
comment_list.append(comment)
like_list.append(like)
transmit_list.append(transmit)
time_list.append(time)
x = time_list
label = ['评论数','点赞数','转发数']
color = ['red','blue','green']
list = []
list.append(comment_list)
list.append(like_list)
list.append(transmit_list)
for i in range(3):
plt.plot(x,list[i],c=color[i],label=label[i])
#设置轴标签
plt.xlabel('weibo time shaft')
plt.ylabel('weibo count')
plt.title('肖战微博流量情况')
#设置刻度
#解决中文显示问题
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False
#显示多图例legend
plt.legend()
#显示图
plt.show()
绘制图表是最头疼的地方,希望有会作图的小伙伴可以优化一下我做出来的图,并在评论区留言,小弟不胜感激!
github项目地址:https://github.com/jlysh/weibocn