說完模擬登錄之后呢,現(xiàn)在講述對于手機端新浪的爬取過程,此例講述針對Ajax異步請求內容的爬取,以新浪微博“小黃車”話題下的微博為例
分析過程####
1.爬取入口頁面:http://m.weibo.cn/k/%E5%B0%8F%E9%BB%84%E8%BD%A6?from=feed
2.微博信息所在位置查找
當你進入該話題時,通過查看源代碼發(fā)現(xiàn)里面并沒有頁面上的微博信息,那么這些信息在哪呢?是怎么載入到頁面的呢?打開開發(fā)者工具,當你鼠標滑到頁面底端時繼續(xù)滑動會加載出新的頁面,這個時候會發(fā)現(xiàn)網(wǎng)絡中的XHR請求會對應增加一項,并且查看響應會發(fā)現(xiàn)里面包含了頁面的各種信息。主題微博信息第一頁在cards的第五個對象下的cardgroup中,其余頁面均在cards的第一個對象下的cardgroup中如下圖


發(fā)現(xiàn)頁面內容所在之后就需要構造類似的請求,以得到包含微博信息的響應json文件。
3.請求規(guī)律
那么,又一個問題來了,請求有什么規(guī)律呢?請求可在標題頭中查看,具體可點擊編輯和重發(fā)查看具體信息,具體參數(shù)可在參數(shù)中查看


加載新一頁之后發(fā)現(xiàn)這些請求除了since_id這項參數(shù)是不一樣的之外,其余都是一樣的,也就是說話題下的微博分頁是根據(jù)since_id來確定的,每當頁面滑倒底部時,繼續(xù)往下滑則會發(fā)送新的請求,請求中的since_id標志上一頁加載到哪一條微博,現(xiàn)在應該從哪一條微博開始展示。這樣就實現(xiàn)了分頁,因此,接下來就是找到since_id的內容來源于哪里就可以開始構造請求了,經查看后發(fā)現(xiàn)每一個請求的since_id內容都可以在前一項請求中的響應中找到

代碼講解####
1.思路介紹
首先構造請求,第一頁是沒有since_id參數(shù)的,所以除since_id外的請求參數(shù)可固定,since_id則通過每一次讀取響應內容中的since_id動態(tài)替換,然后成功讀取響應內容后(響應內容為json)用python內置json庫載入后,最后就可以方便提取想要的內容了。
2.源代碼
# -- coding: utf-8 --
import urllib
import urllib2
from bs4 import BeautifulSoup
import re
import os
import xlwt
import xlrd
from xlutils.copy import copy
import time
import string
import datetime
import sys
import shutil
import codecs
import traceback
import json
class WeiboContent:
'''
output:
info_list = [(time, user_name, source, user_statuses_count, user_followers_count, user_follow_count,
user_verified, user_verified_type, user_urank, location, content, urls, pic_num, audios, mention)]
'''
def readHtml(self):
try:
info_list = []
user_agent = 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0'
cookies = '"_T_WM=...."' #這里的cookie直接從瀏覽器中粘過來了,具體可參考上一篇文章
headers = { 'User-Agent' : user_agent , 'cookie': cookies}
page = 1
#構造固定的一些參數(shù)
form_data = {
'extparam' : '小黃車',
'from' : 'feed',
'luicode' : '10000011',
'lfid' : '100808b0a0455a95cc4937460d29aa3076aec4',
'containerid' : '100808topic'
}
since_id = ''
#這里是以since_id為循環(huán)終止條件,最后一頁沒有since_id,所以當獲取出錯時跳出循環(huán)
while page:
if page > 1:
form_data['since_id'] = since_id
form_data['containerid'] = containerid
#將form_data的鍵值對轉換為以連接符&劃分的字符串
formData = urllib.urlencode(form_data)
url = 'http://m.weibo.cn/api/container/getIndex?'
#構造request請求
request = urllib2.Request(url = url, headers = headers, data = formData)
index_doc = urllib2.urlopen(request).read()
#使用json.loads()將獲取的返回內容轉換成json格式
index_json = json.loads(index_doc)
try:
since_id = index_json['pageInfo']['since_id']
except:
traceback.print_exc()
print 'end get data,since-id wrong'
break
if page == 1:
card_group = index_json['cards'][5]['card_group']
else:
card_group = index_json['cards'][0]['card_group']
#遍歷提取card_group中每一條微博的信息
for card in card_group:
try:
mblog = card['mblog']
#針對時間中的分鐘前和今天做標準化時間處理
time = mblog['created_at']
if len(re.findall('分鐘前'.decode('utf-8'), time)) == 1:
num = int(time.split('分鐘前'.decode('utf-8'))[0])
time = datetime.datetime.now() - datetime.timedelta(minutes = num)
time = time.strftime('%m-%d %H:%m')
if len(re.findall('今天'.decode('utf-8'), time)) == 1:
hour = time.split('今天'.decode('utf-8'))[1]
time = '04-19' + hour #這里寫的比較隨意,直接給出日期,可利用和時間有關函數(shù)動態(tài)獲取爬取當天的日期
#獲取微博內容,如果為長微博需獲取全文的鏈接地址進一步獲取微博全部內容
isLongText = mblog['isLongText']
text = mblog['text']
if isLongText:
text_id = mblog['id']
text_%text_id
text_req = urllib2.Request(url = text_href, headers = headers)
text_doc = urllib2.urlopen(text_req).read()
text_json = json.loads(text_doc)
text = text_json['longTextContent']
#提取微博內容的一些特征信息
text_soup = BeautifulSoup(text,"html.parser")
content = text_soup.get_text()
urls = len(re.findall('small_web_default.png', text)) + len(re.findall('small_article_default.png', text))
audios = len(re.findall('small_video_default.png', text))
mention = len(re.findall('<a.href.*?@.*?</a>', text))
topic = len(re.findall('<a.*?href.*?#.*?#</a>', text))
source = mblog['source']
reposts_count = mblog['reposts_count']
comments_count = mblog['comments_count']
attitudes_count = mblog['attitudes_count']
#提取用戶信息
user = mblog['user']
user_id = user['id']
user_gender = user['gender']
user_statuses_count = user['statuses_count'] #微博數(shù)
user_followers_count = user['followers_count'] #粉絲數(shù)
user_follow_count = user['follow_count'] #關注數(shù)
user_verified = user['verified']
#verified_type:-1普通用戶 0名人 1政府 2企業(yè) 3媒體 4校園 5網(wǎng)站 6應用 7團體 8待審企業(yè) 200會員 220達人 0黃V用戶 其他藍v用戶 10是微女郎
user_verified_type = user['verified_type']
user_urank = user['urank'] #微博等級
is_location = len(re.findall('small_location_default.png', text))
if is_location:
location = text_soup.find_all("span", {"class": "surl-text"})[-1].get_text()
else:
location = ''
pic_num = len(mblog['pics']) if mblog.has_key('pics') else 0
info = (time, user_id, source, user_gender, user_statuses_count, user_followers_count, user_follow_count, \
user_verified, user_verified_type, user_urank, location, content, urls, pic_num, \
audios, mention, topic, reposts_count, comments_count, attitudes_count)
info_list.append(info)
except Exception,e:
traceback.print_exc()
print '----'
print page
print 'since---'
print since_id
continue
print 'get page:%d'%page
page += 1
return info_list
except Exception,e:
traceback.print_exc()
return info_list
#存入excel
def save_excel(self):
info_list = self.readHtml()
#print info_list
file = xlwt.Workbook()
sheet1 = file.add_sheet(u'sheet1',cell_overwrite_ok=True)
sheet1.col(0).width=256*22
sheet1.col(11).width=256*100
style = xlwt.easyxf('align: wrap on, vert centre, horiz center')
row0 = ('time', 'user_id', 'source', 'user_gender', 'user_statuses_count', 'user_followers_count', \
'user_follow_count', 'user_verified', 'user_verified_type', 'user_urank',\
'location', 'content', 'urls', 'pic_num', 'audios', 'mention', 'topic', 'reposts_count', 'comments_count', 'attitudes_count')
for i in range(0,len(row0)):
sheet1.write(0,i,row0[i],style)
for i in range(0,len(info_list)):
for j in range(0,len(info_list[i])):
sheet1.write(i+1, j, info_list[i][j], style)
file.save('D:/dataset/USele_topic.xls')
print 'save success'
#*******************************************************************************
# 程序入口 預先調用
#*******************************************************************************
if __name__ == '__main__':
WeiboContent().save_excel()