python爬蟲之爬取微博《肺炎患者求助》超話信息

學校有個老師想研究微博《肺炎患者求助》的文本信息,他給了我一個PC端的鏈接,找我幫忙寫爬蟲,把鏈接上所有求助信息全部爬下來,我查看一共有21頁,日期爲2020年2月1日~2020年3月13日;經過一番檢查後,我決定自己從移動端網頁入手,其一:因爲我上個月爬取過微博的《戰疫情》,可以節約很多時間去分析網頁結構;其二:移動端使用的是ajax加載,請求得到json數據,速度快得很多。在這裏我就不去詳細講解這次的實戰了,如果感興趣的話可以結合我上次的實戰經驗閱讀。

曾經實戰項目: python爬蟲爬取微博之戰疫情用戶評論及詳情

PC端網頁: https://weibo.com/p/1008084882401a015244a2ab18ee43f7772d6f/super_index

移動端網頁: https://m.weibo.cn/p/index?containerid=1008084882401a015244a2ab18ee43f7772d6f&luicode=10000011&lfid=100103type%3D1%26q%3D肺炎患者求助超話

操作環境: windows10, python37, jupyter

實現思路:

  1. 打開《肺炎患者求助》首頁,進行抓包,分析它的json結構;
  2. 通過抓包可以拿到所有的文章的:用戶,發佈時間,文章ID轉發量,評論量,點贊量等等,但是無法拿到超出發佈內容範圍的隱藏部分;
  3. 隱藏內容超出部分的文章有一個“全文”的標識,鼠標點擊後即可展開,但是我們只需要自己通過上面拿到的文章ID拼接出它的完整鏈接,即可訪問詳情信息;同時,是否要進行訪問詳情信息可以通過“【姓名】”是否存在進行,這樣可以節約程序的時間,提高效率。
  4. 使用正則表達式匹配出上面的內容的詳細信息,按照:“姓名、年齡、城市、地址、時間、聯繫方式、緊急聯繫人、病情描述" 這樣來存儲;
  5. 下一個API中的區別在 since_id ,可以在當前API中獲取,變化 since_id 就可以不斷的進行下一個json數據的獲取;
  6. while True 中設置了兩個跳出死循環的條件,一個爲找不到下一個 since_id 時跳出循環,第二個爲 since_id 以前面的重複時跳出死循環。
  7. 結果寫入CSV.
import requests, csv, time, re

startTime = time.time() #記錄起始時間
csvfile = open('./微博疫情求助+數據匹配.csv', 'a', newline='', encoding = 'utf-8-sig')
writer = csv.writer(csvfile)
writer.writerow(('文章ID', '發佈時間', '轉發量', '評論數', '點贊數', '內容','姓名', '年齡', '城市', '小區', '患病時間', '病情描述', '聯繫方式', '其他緊急聯繫人'))

index_url = "https://m.weibo.cn/api/container/getIndex?containerid=1008084882401a015244a2ab18ee43f7772d6f_-_feed&luicode=10000011&lfid=100103type%3D1%26q%3D%E8%82%BA%E7%82%8E%E6%82%A3%E8%80%85%E6%B1%82%E5%8A%A9%E8%B6%85%E8%AF%9D&display=0&retcode=6102"

next_id_list = []

def regular(find_title):
    name = re.findall('.*?【姓名】(.*?)<', find_title)
    if len(name) != 0:
        name = ''.join(name)
    else:
        name = ""

    age = re.findall('.*?【年齡】(.*?)<', find_title)
    if len(age) != 0:
        age = ''.join(age)
    else:
        age = ""

    city = re.findall('.*?【所在城市】(.*?)<', find_title)
    if len(city) != 0:
        city = ''.join(city)
    else:
        city = ""
    village = re.findall('.*?【所在小區、社區】(.*?)<', find_title)
    if len(village) != 0:
        village = ''.join(village)
    else:
        village = ""
    ill_time = re.findall('.*?【患病時間】(.*?)<', find_title)
    if len(ill_time) != 0:
        ill_time = ''.join(ill_time)
    else:
        ill_time = ""
    describe = re.findall('.*?【病情描述】(.*?)<', find_title)
    if len(describe) != 0:
        describe = ''.join(describe)
    else:
        describe = ""
    phone = re.findall('.*?【聯繫方式】(.*?)<', find_title)
    if len(phone) != 0:
        phone = ''.join(phone)
    else:
        phone = ""
    other_way = re.findall('.*?【其他緊急聯繫人】(.*?)<', find_title)
    if len(other_way) != 0:
        other_way = ''.join(other_way)
    else:
        other_way = ""
    return name, age, city, village, ill_time, describe, phone, other_way

while True:
    html = requests.get(url = index_url)
    try:
        since_id = html.json()["data"]["pageInfo"]["since_id"]
    except:
        break
    index_url = index_url + "&since_id=" + str(since_id)
    # 防止since_id重複,當since_id重複時跳出循環
    if since_id in next_id_list:
        break
    else:
        next_id_list.append(since_id)
    # 提取所有信息    
    for i in html.json()["data"]["cards"]:        
        try:
            for j in i["card_group"]:
                title_id = j["mblog"]["id"] #文章ID
                created_time = j["mblog"]["created_at"] #發佈時間
                sharing = j["mblog"]["reposts_count"] #轉發量
                comments_count = j["mblog"]["comments_count"] #評論數
                great = j["mblog"]["attitudes_count"] #點贊
                comments_html = j["mblog"]["text"] # 內容,html形式的
                if ">全文<" in comments_html:
                    all_url = "https://m.weibo.cn/status/" + title_id #打開全文,獲取具體信息
                    html_text = requests.get(url=all_url).text
                    # 話題內容
                    find_title = re.findall('.*?"text": "(.*?)",.*?', html_text)[0]
                    comment_text = re.sub('<(S*?)[^>]*>.*?|<.*? />', '', find_title) #正則匹配掉html標籤
                    if "【姓名】" in find_title: 
                        result = regular(find_title)
                else:
                    comment_text = re.sub('<(S*?)[^>]*>.*?|<.*? />', '', comments_html) #正則匹配掉html標籤
                    if "【姓名】" in find_title:                        
                        result = regular(find_title)
                if "【姓名】" in comments_html: 
                    writer.writerow((title_id, created_time, sharing, comments_count, great, comment_text, result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7]))
                else:
                    writer.writerow((title_id, created_time, sharing, comments_count, great, comment_text))
        except:
            pass

    print ("正在爬取:", since_id)
    
csvfile.close() #關閉文件
endTime =time.time()#獲取結束時的時間
useTime =(endTime-startTime)/60
print ("該次所獲的信息一共使用%s分鐘"%useTime)

jupyter運行結果:
在這裏插入圖片描述


CSV結果:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章