有时候在浏览器可以看到正常的网页数据,但是requests得不到数据,这是由于数据可能是通过Ajax加载的,也可能是经过JS和特定算法计算后生成的。
浏览网页的时候,我们会发现很多网页都有“下滑查看更多”的选项,这个过程就是Ajax加载的过程。【都是通过JS实现】
- 发送请求【Type为XHR】
- 解析内容
- 渲染网页
爬取微博
分析请求
是一个get请求,请求链接为:https://m.weibo.cn/api/container/getIndex?
后面跟着5个参数:
- uid
- luicode
- lfid
- containerid,爬取谁的微博
- page,指定获取哪个页面
分析响应
响应为json数据,data/cards/mblog下为响应内容:
- id
- text为微博文字
- attitudes_count为点赞人数
- reposts_count为转发数
- comments_count为评论人数
图片存在data/cards/mblog/pics/i/url下面,其中i为0-8数字。
抓取页面
# -*- coding: utf-8 -*-
from urllib.parse import urlencode
from pyquery import PyQuery as pq
from pymongo import MongoClient
import requests
import os
base_url = 'https://m.weibo.cn/api/container/getIndex?'
headers={
'Referer': 'https://m.weibo.cn/u/1749127163?uid=1749127163&luicode=10000011&lfid=100103type%3D1%26q%3D%E9%9B%B7%E5%86%9B',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36',
'X-Requested-With':'XMLHttpRequest',
}
def get_page(page):
params={
'uid': '1749127163',
'luicode': '10000011',
'lfid': '100103type=1&q=雷军',
'containerid': '1076031749127163',
'page': page
}
url=base_url+urlencode(params)
try:
response=requests.get(url,headers=headers)
if response.status_code==200:
return response.json()
except requests.ConnectionError as e:
print('Error',e.args)
#解析网页
def parse_page(json):
if json:
items=json.get('data').get('cards')
for item in items:
item = item.get('mblog')
#首页cards第二条不含mblog微博信息,要跳过
if item == None:
continue
#图片
pics=item.get('pics')
imgs={}
if pics!=None:
for pic in pics:
imgs[pic.get('pid')] = pic.get('large').get('url')
yield {
'id':item.get('id'),
'text':pq(item.get('text')).text(),
'attitudes':item.get('attitudes_count'),
'comments':item.get('comments_count'),
'reposts':item.get('reposts_count'),
'imgs':imgs
}
#保存图片
def save_image(mid,pid,url):
if not os.path.exists(mid):
os.mkdir(mid)
try:
response=requests.get(url)
if response.status_code==200:
file_path='{0}/{1}.{2}'.format(mid,pid,'jpg')
with open(file_path,'wb') as f:
f.write(response.content)
except requests.ConnectionError:
print('Failed to save image...')
if __name__ == '__main__':
#保存信息
client = MongoClient()
db = client.weibo#指定数据库
collection = db.weibo#指定集合
collection.delete_many({})#删除所有
#抓取1和2页的微博
for page in range(1,3):
json=get_page(page)
results=parse_page(json)
for result in results:
#保存到数据库
collection.insert(result)
#保存图片
imgs=result['imgs']
for it in imgs:
save_image(result['id'],it,imgs[it])
#检查数据库数据
outs=collection.find({})
for it in outs:
print(it)
print('微博数目:',collection.count_documents({}))
"""
抓取结果如下,每页10条,这里只显示3条
{'_id': ObjectId('5cdae308a9ab7b822478f045'), 'id': '4368918258900032', 'text': '小米9全息幻彩色,真棒!', 'attitudes': 2466, 'comments': 1615, 'reposts': 189, 'imgs': {}}
{'_id': ObjectId('5cdae308a9ab7b822478f046'), 'id': '4371901444759517', 'text': '我试试#Redmi K20# ,非常好!', 'attitudes': 1411, 'comments': 823, 'reposts': 78, 'imgs': {}}
{'_id': ObjectId('5cdae308a9ab7b822478f047'), 'id': '4371814035208997', 'text': 'Flagship Smartphone Killer', 'attitudes': 1822, 'comments': 1055, 'reposts': 120, 'imgs': {}}
"""
存储信息
from pymongo import MongoClient
client = MongoClient()
db = client['weibo']
collection = db['weibo']
def save_to_mongo(result):
if collection.insert(result):
print('Saved to Mongo...')
多线程
如下多线程存在线程安全,存入数据库的数据有重复,最终微博条数变少。
from multiprocessing.pool import Pool
def main(page):
#保存信息
client = MongoClient()
db = client.weibo#指定数据库
collection = db.weibo#指定集合
#collection.delete_many({})#删除所有
json=get_page(page)
results=parse_page(json)
for result in results:
#保存到数据库
collection.insert(result)
#保存图片
imgs=result['imgs']
for it in imgs:
save_image(result['id'],it,imgs[it])
if __name__ == '__main__':
client = MongoClient()
db = client.weibo#指定数据库
collection = db.weibo#指定集合
collection.delete_many({})#删除所有
pool=Pool()
pages=([x for x in range(0,2)])
pool.map(main,pages)
pool.close()
pool.join()
#检查数据库数据
outs=collection.find({})
for it in outs:
print(it)
print('微博数目:',collection.count_documents({}))