Python單線程爬取QQ空間說說存入MySQL並生成詞雲(超詳細講解,踩坑經歷)

看了網上的許多博客,基本上都是一個樣,基本的知識也沒詳細解釋,我這次也想跟大家仔細分析一下,自己還是要有一定爬蟲基礎,本人技術有限,如果本文哪有錯誤或不夠準確的地方,還望大牛們指點ヾ(๑╹◡╹)ノ"


一、環境配置:

  • Python 3.6
  • selenium (注意:先配置好自己瀏覽器的驅動,下載地址看下面)
  • pymysql
  • re
  • requests

點擊下載chrome的---->Chrome_webdriver
點擊下載Firefox的---->Firefox_webdriver
點擊下載IE的---->IE_webdriver

先來張效果圖看看效果
ki2cDJ.md.png

二、思路:

作爲一個菜雞學了一點爬蟲,就想做一個好友的說說分析,最開始我以爲這個爬蟲很簡單幾十行就可以搞定,然而忽略了一些東西。。。。(先賣個關子)


先說說整個過程的想法:
kFAq54.png
看起來是不是很簡單?(手動dog)那現在我們就來按步驟操作一下

1.找到包含好友的QQ信息的url(這裏也有兩種方法)

  • 法一
    先點開好友這一欄,通過親密度的排行來獲取,這裏我們點開F12,選中Network
    一般這種信息都在XHR或者JS類型裏面,大家可以在這裏面找找,通過一會的尋找我們就發現friend_ship開頭這xhr裏面的items_list就包含了好友的QQ號和姓名,但是此方法獲取的qq不全,只是大部分的qq
    kFEYMq.png
    kFE4Fe.png
  • 法二:
    點擊頁面最上面的設置按鈕,滑動可見好友,通過js的結果分析,隨着下滑請求的url的頁數都在變化,我們只要每次修改下頁數的參數就可以獲取所有好友的QQ,這個方法可以獲取所有的好友的qq,但對於qq好友很少的朋友來說,此方法不適用


2.找到包含好友的說說的url

我們先隨便點進一個好友的空間進行分析

點進去過後,我們F12 進行分析,發現一頁最多存20條說說,以此我們可以通過說說總數(re提取)來算出一共有多少頁,然後通過構造url來獲取


通過以上的分析過後我們開始獲取url:

我們先看看獲取qq的第一種方法的url:

https://user.qzone.qq.com/proxy/domain/r.qzone.qq.com/cgi-bin/tfriend/friend_ship_manager.cgi?uin=你的QQ號&do=1&rd=0.55484478707938&fupdate=1&clean=1&g_tk=1376935160&qzonetoken=6e4e0b063e3f00421d98df35b330c8bb2158bb8697e5dc7a85a65b379407706960f0b1c422f9a26879&g_tk=1376935160

我們分析一下這裏面每次登錄都在變的參數

  • g_tk (空間加密算法)
  • qzonetoken (空間源碼裏面的參數)

那這兩個參數我們要怎麼獲取呢?爲什麼每次登錄這兩個參數的都在變呢?

我們首先先要了解一下---->cookie
在看看session的基本概念

快速查看 cookies 的方法:按F12進入瀏覽器的開發者模式——console——在命令行輸入javascript:alert(document.cookie),再回車即可看見

所以我們登錄過後,每次都訪問url的時候都要保持着參數不變,也就是說cookie不能變
每次都要是同一個cookie(就相當於每次都是以你的身份保持着登錄狀態去訪問他人空間),否則就會出現以下情況↓


理解好以上的幾個問題過後,問題就解決了一大部分了
接着我們分析g_tk參數,在自己qq空間主頁 F12 點JS類型文件,找到以下文件,查看Preview部分,分析一下其中的代碼

其實這個程序的意思, 還是直接上代碼吧


def get_tk(cookie):
    hashes = 5381       
    for i in cookie['p_skey']:    #提取cookie中p_skey每個字母
        hashes += (hashes << 5) + ord(i)  #加密過程,ord()將 字符轉化爲ASCII碼
                                  # << 二進制 左移運算 左移幾位就相當於乘以2的幾次方
    return hashes & 2147483647  #二進制 與運算
    # 比如  2&3 轉爲二進制  10&11
	#   都是1結果爲1,否則爲0   
	#    所以二進制算出來是  10   返回2
	#   還不懂的朋友,還是自行Baidu吧

隨着我們分析第二個參數qzonetoken
這個參數很好獲取,在我們空間主頁右鍵查看網頁源代碼,Ctrl+F查找下可以找到,之後我們可以通過正則提取

ok,理解了上面的全部,基本就完成了80%了,接下來我們開始代碼實現

三、代碼實現:

先導入第三方庫

import re, requests
import time, pymysql

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
  1. 首先是登錄,我們這裏用selenium模擬瀏覽器實現

def login():
    driver = webdriver.Chrome()  # 傳入瀏覽器對象
    wait = WebDriverWait(driver, 5)  # 顯式等待
    driver.get('https://qzone.qq.com/')
    driver.switch_to_frame('login_frame')       #切換到登錄窗口
    input = wait.until(EC.presence_of_element_located((By.ID, 'switcher_plogin')))# 顯式等待 找到賬號密碼登錄按鈕
    time.sleep(1)
    input.click()     # 交互點擊
    driver.find_element_by_id('u').clear()  #清空裏面的內容
    driver.find_element_by_id('u').send_keys('your_qq')   #傳入你的QQ
    time.sleep(3)
    driver.find_element_by_id('p').clear()   
    driver.find_element_by_id('p').send_keys('your_password')  #傳入你的密碼
    button = driver.find_element_by_id('login_button')   #找到登錄按鈕
    time.sleep(3)  
    button.click()
    time.sleep(1)
    driver.switch_to.default_content()  # 將frame重新定位回來,不然後續會出錯
    return driver

  1. 通過傳回來的driver對象獲取網頁源代碼和cookies

通過源代碼獲取qzonetoken參數

	def get_qzonetoken(html):
    paa = re.compile(r'window\.g_qzonetoken = \(function\(\)\{ try\{return "(.*?)";\} catch\(e\)', re.S)
    res = re.findall(paa, html)[0]  # 因爲返回的是列表形式,所以只取第一個元素
    return res

注意:driver.get_cookies()獲取的cookies是散的,所以要進行以下操作:

def get_tk(cookie):  #加密過程
    hashes = 5381
    for i in cookie['p_skey']:
        hashes += (hashes << 5) + ord(i)
    return hashes & 2147483647
    
  cookies = driver.get_cookies()
	 for item in cookies:
        cookie[item['name']] = item['value']   #將對應表達聯繫起來 
         #  上一步不懂的可以把 cookies的值輸出來看一下
    g_tk = get_tk(cookie)

3.將cookies傳給requests,以保證都是在登錄狀態(最關鍵

def back_session(driver):
    mysession = requests.session()  #  建立一個session對話
    cookies = driver.get_cookies()
    cookie = {}
    for item in cookies:
        cookie[item['name']] = item['value']
    headers = {
        'authority': 'user.qzone.qq.com',
        'referer': 'https://qzone.qq.com/',
        'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
        'accept-encoding': 'gzip, deflate, br',
        'accept-language': 'zh-CN,zh;q=0.9',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36'
    }
    c = requests.utils.cookiejar_from_dict(cookie, cookiejar=None, overwrite=True) 
     # 將字典轉化爲cookiejar形式
    mysession.headers = headers  # 請求頭,防止反爬
    mysession.cookies.update(c)  # 更新cookies
    return mysession   # 返回帶cookies的requests
  1. 存入MySQL
connection = pymysql.connect(host='your_host', port=3306, user='你的賬戶', passwd='你的密碼', db='your_database')
connection.autocommit(True)   #開啓自動提交 不然每次執行

def save_mysql(say, stime, QQ, connection):  #這裏我存入說說、說說時間、qq號
    stime = str(stime)
    content = str(say)
    QQ = str(QQ)
    sql = 'insert into qq values ("{}","{}","{}")'.format(content, stime, QQ)
    connection.query(sql)
#  數據庫建表的時候  一定要把字符集改成utf8

看看效果圖,爬了40多分鐘,四萬多條數據,有點小慢。。。,很慢。大家可以嘗試下多線程爬取


完成以上步驟之後整個框架就都搭好了,其餘數據的提取大家就先自己完成了吧(本文最後會給出GitHub地址),也希望大家看思路過後,自己操作,不僅僅是copy、paste and run

導出某個好友的數據庫,用Notepad++過濾一些數據後,通過詞雲分析

import jieba
from matplotlib import pyplot as plt
from wordcloud import WordCloud
from PIL import Image
import numpy as np

path = r'your_data.text_path'
font = r'C:\Windows\Fonts\simkai.TTF'  #  字體path

text = (open('C:/Users/hp/Desktop/233.txt', 'r', encoding='utf-8')).read() # 如果是中文的話encoding換成utf8
cut = jieba.cut(text)  # 分詞
string = ' '.join(cut)
print(len(string))
img = Image.open('your_photo_path')  # 打開圖片
img_array = np.array(img)  # 將圖片裝換爲數組
stopword = ['xa0']  # 設置停止詞,也就是你不想顯示的詞,這裏這個詞是我前期處理沒處理好,你可以刪掉他看看他的作用
wc = WordCloud(
    scale=4,  #清晰度
    background_color='white',  #背景顏色
    max_words=400,    #最多單詞
    width=1000,				
    height=800,
    mask=img_array,
    font_path=font,
    stopwords=stopword   # 停用詞
)
wc.generate_from_text(string)  # 繪製圖片
plt.imshow(wc)
plt.axis('off')
plt.figure()
#plt.show()  # 顯示圖片
wc.to_file('F:/3.png')  # 保存圖片


最後我麼就分析到以下圖片,字越大說明出現次數最多

最後貼上我的代碼鏈接 https://github.com/Leaderzhangyi/QQspider 希望大家能夠共同改進

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