python3編寫網絡爬蟲13-Ajax數據爬取

1、Ajax數據爬取javascript

1. 簡介:Ajax 全稱Asynchronous JavaScript and XML 異步的Javascript和XML。
它不是一門編程語言,而是利用JavaScript在保證頁面不被刷新,頁面連接不改變的狀況下與服務器交換數據,
得到數據後,再利用JavaScript改變頁面。java

示例:新浪微博 熱門python

2. 基本原理ajax

2.1 發送請求mongodb

JavaScript能夠實現頁面交互功能 Ajax也不例外 它是由JavaScript實現的,實際上執行了以下代碼數據庫

var xmlhttp; if(window.XMLHttpRequest){   # code for IE7+,Firefox,Chrome,Opera,Safari   xmlhttp = new XMLHttpRequest();#新建對象 }else{#code for IE6,IE5   xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.onreadystatechange = function(){#設置監聽   if(xmlhttp.readyState==4 && xmlhttp.status==200){     document.getElementById("myDiv").innerHTML = xmlhttp.responseText;   } } xmlhttp.open("POST","/ajax/",true); xmlhttp.send();#發送請求

 

這是javascript對ajax最底層的實現,新建XMLHttpRequest對象 調用onreadystatechange屬性設置監聽
調用open和send方法發送請求。編程

以前用python發送請求能夠獲得響應結果 但這裏的請求發送變成了javascript來完成,
因爲設置了監聽 服務器響應結果時,onreadystatechange屬性會被觸發 而後解析裏面的內容。json

2.2 解析內容api

獲得響應內容後,onreadystatechange屬性對應的方法便會觸發,利用xmlhttp的responseText屬性接收。
相似python中利用requests向服務器發送請求 而後獲得響應結果的過程。
返回的結果多是HTML 也多是JSON 只須要在js中作進一步處理 例如返回json 能夠進行解析和轉化。瀏覽器

2.3 渲染頁面

js有改變網頁內容的能力,解析完響應內容後 調用js裏面document.getElementById().innerHTML 改變某個元素內的源代碼
這樣網頁的內容就改變了 簡稱DOM操做

2.4 總結 3個步驟都是js完成的 微博下拉實際上就是js向服務器發送一個Ajax請求 而後獲取服務器響應內容
解析並渲染到網頁中。真實數據都是js一次次ajax請求獲得的。
若是須要抓取數據 就要知道 請求怎麼發送的? 發送到哪裏?發送了哪些參數?


3. Ajax分析方法

3.1 查看方法

測試地址:

https://m.weibo.cn/u/1195242865


瀏覽器開發者工具 ajax請求類型爲xhr
Request Headers信息爲 X-Requested-With: XMLHttpRequest 標記此請求爲Ajax請求

3.2 過濾請求

點擊開發者工具Network -> XHR 過濾爲ajax請求 不斷滑動頁面 出現新的請求


發送請求地址:

https://m.weibo.cn/api/container/getIndex?type=uid&value=1195242865&containerid=1076031195242865&since_id=4311085060664535

參數:
type: uid
value: 1195242865
containerid: 1076031195242865
page:1

4. 提取結果

from urllib.parse import urlencode import requests from pyquery import PyQuery as pq base_url = 'https://m.weibo.cn/api/container/getIndex?'#請求url的前半部分
 headers = {   'Host':'m.weibo.cn',   'Referer': 'https://m.weibo.cn/u/1195242865',   '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',   'X-Requested-With': 'XMLHttpRequest', } # 構造url 發送請求
def get_page(page):   params = {     'type': 'uid',     'value': '1195242865',     'containerid': '1076031195242865',     '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) #解析方法 提取id 正文 贊數 評論數 轉發數 遍歷cards 獲取mblog中的各個信息

def parse_page(json):   if json:     items = json.get('data').get('cards')     for item in items:     # print(item)
    item = item.get('mblog')     if item:       weibo = {} #定義空字典接收數據
      weibo['id'] = item.get('id')       weibo['text'] = pq(item.get('text')).text()       weibo['attitudes'] = item.get('attitudes_count')       weibo['comments'] = item.get('comments_count')       weibo['reposts'] = item.get('reposts_count')       yield weibo #遍歷page 一共10頁 將提取到的結果打印輸出

if __name__ == '__main__':   for page in range(1,3):     json = get_page(page)     results = parse_page(json)     for result in results:       print(result)

5. 添加到mongodb數據庫中

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')

 

查看mongo內容

啓動mongo服務 查看庫 show dbs; 查看當前在哪一個庫 db.getName(); 進入庫 use dbname;
查看數據 db.dbname.find(); 刪除當前所在庫 db.dropDatabase();


至此分析模擬Ajax請求爬取微博列表完成 爬取結果不重要 還有好多地方能夠完善 好比動態計算頁碼,查看微博全文等等。
主要是讓你們瞭解抓取原理

 

實例:爬取今日頭條街拍圖片

地址:http://www.toutiao.com 關鍵字 :街拍

offset: 0 format: json keyword: 街拍 autoload: true count: 20 cur_tab: 1
from: search_tab pd: synthesis

基本代碼

import requests import json import time import re import os from random import choice from hashlib import md5 url = "https://www.toutiao.com/search_content/?" header = {   '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', } keyword = '街拍' has_gallery_lists = [] no_gallery_lists = [] def SearchPageParser(offset=0):   payload = {     'offset': offset,     'format': 'json',     'keyword': keyword,     'autoload': 'true',     'count': 30,     'cur_tab': 1,     'from': 'search_tab'   }   count = 0   try:     response = requests.get(url, headers=header, params=payload)     content = None     #打印拼接請求後的url     # print("Parser " + response.url)
    if response.status_code == requests.codes.ok:       content = response.text       data = json.loads(content)       if not data:         return

      for article in data.get('data'):         if True == article.get('has_gallery') and True == article.get('has_image'):           has_gallery_lists.append(article.get('article_url'))           count += 1

        if False == article.get('has_gallery') and True == article.get('has_image'):           no_gallery_lists.append(article.get('article_url'))           count += 1

        return count    except Exception as e:     print(e)     return

#保存本地函數
def SaveImage(imageURL,title): #判斷文件夾是否存在
  if not os.path.exists(title):     os.mkdir(title)   try:     response = requests.get(imageURL)     if response.status_code == 200:       file_path = '{0}/{1}.{2}'.format(title, md5(response.content).hexdigest(), 'jpg')       # 判斷是否重名
      if not os.path.exists(file_path):         with open(file_path,'wb') as f:         f.write(response.content)       else:         print('Already Downloaded',file_path)   except:     print('Failed to Save Image') #第一種頁面
def HasGalleryParser():   if 0 == len(has_gallery_lists):     return

  # 正則
  pattern = re.compile('gallery: JSON\.parse\("(.*?)max_img', re.S)   pattern_t = re.compile('<title>(.*?)</title>', re.S)   while has_gallery_lists:     this = has_gallery_lists.pop()   try:     response = requests.get(this, headers=header)     content = None     if response.status_code == requests.codes.ok:       content = response.text       data = pattern.findall(content)       pattern_t.findall(content)       if data:       #去掉多餘符號
        data = data[0][:-4].replace('\\', '') + ']}'         img_urls = json.loads(data).get('sub_images')         title = "".join(pattern_t.findall(content))         for img_url in img_urls:         #保存函數
          SaveImage(img_url.get('url'),title)       else:         print("BadPageURL[GalleryParser, {0:s}]".format(this))   except Exception as e:     print(e)     return   time.sleep(0.25) #第二種頁面
def NoGalleryParser():   if 0 == len(no_gallery_lists):     return

  while no_gallery_lists:     this = no_gallery_lists.pop()     #正則匹配
    pattern = re.compile('&lt;img src&#x3D;&quot;(.*?)&quot;', re.S)     pattern_t = re.compile('<title>(.*?)</title>',re.S)     try:       response = requests.get(this, headers=header)       content = None       if response.status_code == requests.codes.ok:         content = response.text         img_urls = pattern.findall(content)         img_title = "".join(pattern_t.findall(content))         if img_urls:           for img_url in img_urls:             #保存函數
            SaveImage(img_url,img_title)         else:           # 過濾地址
          print("BadPageURL[NoGalleryParser, {0:s}]".format(this))     except Exception as e:       print(e)       return   time.sleep(0.25) if __name__ == "__main__":   #計數變量
  x, count = 0, 0   # 獲取頭條頁面
  cnt_urls = SearchPageParser(x)   while count < 20 and cnt_urls:     cnt_urls = SearchPageParser(x + 20)     count += cnt_urls     x += 20     time.sleep(0.55)     #打印分頁地址     # print("Get {0:d} URL(s) in total.".format(count))   # 分析頁面
  HasGalleryParser()   NoGalleryParser()
相關文章
相關標籤/搜索