最近自学了Python,所以就想把自己学的东西分享出来,写的很初级,如有错误请指正,谢谢
本文仅供学习!!!
从微博中抓取的数据我用了两种方式保存,一种是mongo,一种是mysql.
项目结构
__init__.py 是配置文件,包括日志配置,mongo配置以及mysql配置
data_grap.log是打印日志的文件
run.py 是运行Python程序的入口
service.py就是程序的主要业务代码
环境以及微博接口
1. 使用Python3以上
2. mysql编码为utf8mb4(抓取的数据有表情)
3. 因为抓取数据,我要模拟浏览器请求接口,所以需要抓取的接口,以及请求头,具体如下
detail_url = 'https://m.weibo.cn/detail/'
host = 'm.weibo.cn'
base_url = 'https://%s/api/container/getIndex?' % host
# 这里的user_agent是网上找的
user_agent = 'User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, ' \
'like Gecko) Version/9.0 Mobile/13B143 Safari/601.1 wechatdevtools/0.7.0 MicroMessenger/6.3.9 ' \
'Language/zh_CN webview/0 '
这些数据都是在网上找到,自己可以网页请求微博接口,就可以看到,urser_agent 可能不一样
业务代码
1. 抓取微博数据
# 抓取微博数据
def get_data(page, user_id):
headers = {
'Host': host,
'Referer': 'https://m.weibo.cn/u/%s' % user_id,
'User-Agent': user_agent
}
params = {
'type': 'uid',
'value': user_id,
'containerid': int('107603' + user_id),
'page': page
}
url = base_url + urlencode(params)
try:
res = requests.get(url, headers=headers)
if res.ok == 1:
return res.json()
elif res.status_code == 418:
logger.info("接口冷却中! 无法爬取!")
return '418'
except requests.ConnectionError as e:
logger.info("抓取错误:" + str(e))
finally:
# 微博接口限制请求,睡3秒在请求
time.sleep(3)
以上代码就是模拟浏览器请求访问微博接口的代码,主要包括请求头,参数和请求url.由于微博对接口的访问有限制,频繁请求会返回418状态码,这个意思就是频繁访问,需要等一会才可以.所以我在finally中加了个睡眠.
还有就是有意要注意的就是拼接请求url的时候,参数要使用urlencode处理一下,否则会报错.
2. 分析数据并保存
Python抓取数据最重要的就是分析数据,拿到自己想要的东西,一下是分析抓取数据的代码:
# 分析数据并保存
def analysis_data(json, st, rst):
if json is None or json.get('data') is None or json.get('data').get('cards') is None:
logger.info("当前页没有数据")
return 'None'
items = json.get('data').get('cards')
for item in items:
if item.get('card_type') == 9:
blog = item.get('mblog')
# 判断是否是转发微博
if blog.__contains__('raw_text'):
ret_info = blog.get('retweeted_status')
mb = ret_info.get('text')
# 判断是否过滤
if st == '' and rst == '':
save_data(blog, ret_info)
else:
if blog.get('raw_text').find(st) > 0 or mb.find(rst) > 0 or blog.get('text').find(st) > 0:
save_data(blog, ret_info)
else:
msg = blog.get('text')
# 判断是否过滤
if st == '':
save_data(blog, None)
else:
if msg.find(st) > 0:
save_data(blog, None)
首先说一下这个方法的入参,json就是待处理的json数据,st和rst是抓取的话题,st是获取博主发布的微博,rst是获取博主转发的微博.因为,博主的博文不一定都是自己想要的,所以就加了这个过滤的功能,当然你不传这两个参数就会抓取你指定多少页,就会抓取多少页博主的博文.
这段代码就是处理json文本格式的数据,没什么东西,具体需要自己去浏览器中分析.
3. 保存数据
这里使用两种方式:一种mongo,一种mysql,以下是具体代码:
def save_data(blog, ret_info):
if ret_info is not None:
mb = ret_info.get('text')
data['w_url_0'] = detail_url + ret_info.get('id')
data['w_type'] = '转发微博'
data['w_pics_0'] = save_pics(ret_info)
data['w_content_0'] = pq(mb).text()
if ret_info.get('user') is not None:
data['w_id_0'] = ret_info.get('user').get('id')
data['w_name_0'] = ret_info.get('user').get('screen_name')
else:
data['w_type'] = '发布微博'
msg = blog.get('text')
data['w_pics_1'] = save_pics(blog)
data['w_url_1'] = detail_url + blog.get('id')
data['w_id_1'] = blog.get('user').get('id')
data['w_name_1'] = blog.get('user').get('screen_name')
data['w_content_1'] = pq(msg).text()
data['w_time'] = blog.get('created_at')
# 0代表转发微博; 1:代表发布微博
data['_id'] = ('0' if (data['w_type'] == '转发微博') else '1') + "-" + str(data['w_id_1']) + "-" + str(time.time())
# 使用mongo保存
conn = mongodb.get_collection(collection_name)
conn.save(data)
# 使用mysql保存
save_data_in_mysql(data)
def save_pics(p_info):
p = ''
pics = p_info.get('pics')
if pics is not None:
for pic in pics:
# 字符串拼接图片列表
p += str(pic.get('url')) + ';'
return p
def save_data_in_mysql(value):
sql = 'insert into tb_wb_info (_id, w_id_1, w_id_0, w_name_1, w_content_1, w_url_1, w_pics_1, w_name_0, ' \
'w_content_0, w_url_0, w_pics_0, w_type, w_time, create_time) value ' \
'(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s);'
try:
# 检查SQL连接是否关闭,关闭重连
sql_conn.ping(reconnect=True)
# 游标执行SQL语句
cursor.execute(sql, (value['_id'], value['w_id_1'], value['w_id_0'], value['w_name_1'],
str(value['w_content_1']), value['w_url_1'], value['w_pics_1'], value['w_name_0'],
str(value['w_content_0']), value['w_url_0'], value['w_pics_0'], value['w_type'],
value['w_time'], datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
sql_conn.commit()
except Exception as e:
logger.info('保存mysql错误: ' + str(e))
sql_conn.rollback()
finally:
sql_conn.close()
这是保存数据的代码,具体需要注意已经写上注释了.
4. 源码
1. github源码地址: https://github.com/shawnshawnshawn/python_grab_wb.git
2. 本人邮箱: jiangliuer_shawn@outlook.com. 有问题可以私信,但不能保证会及时回复,望见谅.
这次的分享就到这,下次再见