上回我們講到了基礎(chǔ)的圖片的URL的獲取——Python之Instagram圖片爬蟲(一)亭病,這回將要講的就是獲取加載更多時的圖片URL,從而能夠獲取所屬當(dāng)前用戶的所有的圖片的URL鏈接住涉。
分析頁面
還記得上回我們并沒有點擊更多
這個按鈕战惊,僅僅獲取了首頁的圖片具體鏈接。
在首頁中分析出來的HTML中但两,提取到了這樣的
json
數(shù)據(jù)塊鬓梅。
也成功提取了其中的圖片鏈接,這回讓我們先清空一下Chrome 調(diào)試中Network Tab頁面的跟蹤信息谨湘,緊接著點擊一下更多按鈕绽快。
這時就可以瞧見第一條的請求記錄芥丧,再來點開它的response,查看一下具體的返回內(nèi)容坊罢。
哇续担?可不是json
格式的內(nèi)容,這樣就可以很好的查看到更多的圖片鏈接了活孩。但是查看node的信息物遇,發(fā)現(xiàn)圖片僅僅只有幾張,因此可以猜測這樣的請求絕對不止一個憾儒。當(dāng)我們往下拉時挎挖,發(fā)現(xiàn)Instagram自動加載了新的內(nèi)容,同時發(fā)現(xiàn)了新的請求航夺。
同樣返回熟悉的json數(shù)據(jù)蕉朵,但是問題是它是怎么請求下一次的呢?請求的參數(shù)是什么呢阳掐?
如上圖所示始衅,其中的參數(shù)有這么幾個:
- query_id
- id【包裹在json中】
- first
- after
這幾個參數(shù)中,對比兩次請求的參數(shù)缭保,我們可以看到first
參數(shù)沒有變化汛闸。id
參數(shù)也沒變,依據(jù)經(jīng)驗艺骂,這個參數(shù)一定是隨著不同的Instagram賬號而變化的诸老,但肯定容易獲取。所以難點就是獲取另外兩個參數(shù)钳恕。我們優(yōu)先查看第一次提取的HTML中的json
數(shù)據(jù)庫别伏。
查看上圖,火眼金睛應(yīng)該能看出其中的幾個參數(shù):
- id
- end_cursor 【剛好就是第一次query請求的after參數(shù)】
那么query_id去哪里了忧额?這個確實復(fù)雜厘肮,我們在HTML中搜索發(fā)現(xiàn)并沒有存在這個參數(shù),這時就要分析Instagram的動態(tài)加載的JavaScript代碼睦番。
按照一般的經(jīng)驗类茂,我們查詢JavaScript的代碼通常從網(wǎng)站所屬公司的同源的文件開始,我們先去第一個zh_CN_Common查詢query_id
所對應(yīng)的數(shù)字托嚣,發(fā)現(xiàn)確實出現(xiàn)了一條記錄巩检。
再進行queryId
字符串的搜索,結(jié)果出現(xiàn)好多條示启,于是我們打算進行正則匹配兢哭,但遇到的數(shù)字很多。根據(jù)正則匹配的結(jié)果丑搔,我們發(fā)現(xiàn)了幾個厦瓢,來自我的猜測提揍,前面幾個都是以前的版本號,所以我們選取最后一個煮仇。
代碼
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@File : spider.py
@Time : 2017/8/12 0012 21:22
@Author : Empty Chan
@Contact : chen19941018@gmail.com
@Description:
"""
import re
import json
import os
from lxml import etree
import requests
import click
from urllib import parse
import time
PAT = re.compile(r'queryId:"(\d*)?"', re.MULTILINE)
headers = {
"Origin": "https://www.instagram.com/",
"Referer": "https://www.instagram.com/morisakitomomi/",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/58.0.3029.110 Safari/537.36",
"Host": "www.instagram.com",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"accept-encoding": "gzip, deflate, sdch, br",
"accept-language": "zh-CN,zh;q=0.8",
"X-Instragram-AJAX": "1",
"X-Requested-With": "XMLHttpRequest",
"Upgrade-Insecure-Requests": "1",
}
# jso = {"id": "1179476381", "first": 12, "after": ""}
jso = {"id": "", "first": 12, "after": ""}
BASE_URL = "https://www.instagram.com"
# QUERY = "/morisakitomomi/" # 森咲智美
QUERY = "/_8_jjini/"
NEXT_URL = 'https://www.instagram.com/graphql/query/?query_hash={0}&variables={1}'
proxy = {
'http': 'http://127.0.0.1:38251',
'https': 'http://127.0.0.1:38251'
}
def crawl():
click.echo('start...')
try:
all_imgs_url = []
res = requests.get(BASE_URL + QUERY, headers=headers, proxies=proxy) # , verify=False)
html = etree.HTML(res.content.decode())
all_a_tags = html.xpath('//script[@type="text/javascript"]/text()') # 圖片數(shù)據(jù)源
query_id_url = html.xpath('//script[@crossorigin="anonymous"]/@src') # query_id 作為內(nèi)容加載
click.echo(query_id_url)
for a_tag in all_a_tags:
if a_tag.strip().startswith('window'):
data = a_tag.split('= {')[1][:-1] # 獲取json數(shù)據(jù)塊
js_data = json.loads('{' + data, encoding='utf-8')
id = js_data["entry_data"]["ProfilePage"][0]["graphql"]["user"]["id"]
edges = js_data["entry_data"]["ProfilePage"][0]["graphql"]["user"]["edge_owner_to_timeline_media"]["edges"]
print(edges)
end_cursor = js_data["entry_data"]["ProfilePage"][0]["graphql"]["user"]["edge_owner_to_timeline_media"]["page_info"]["end_cursor"]
has_next = js_data["entry_data"]["ProfilePage"][0]["graphql"]["user"]["edge_owner_to_timeline_media"]["page_info"]["has_next_page"]
for edge in edges:
if top_url and top_url == edge["node"]["display_url"]:
in_top_url_flag = True
break
click.echo(edge["node"]["display_url"])
new_imgs_url.append(edge["node"]["display_url"])
# click.echo(qq.get(node["display_src"], proxies=proxy).status_code)
# 請求query_id
query_content = requests.get(BASE_URL + query_id_url[1], headers=headers, proxies=proxy)
query_id_list = PAT.findall(query_content.text)
for u in query_id_list:
click.echo(u)
query_id = query_id_list[1]
count = 0
# 更多的圖片加載
while has_next and count <= 1:
jso["id"] = id
jso["first"] = 12
jso["after"] = end_cursor
text = json.dumps(jso)
url = NEXT_URL.format(query_id, parse.quote(text))
res = requests.get(url, headers=headers, proxies=proxy)
time.sleep(2)
html = json.loads(res.content.decode(), encoding='utf-8')
has_next = html["data"]["user"]["edge_owner_to_timeline_media"]["page_info"]["has_next_page"]
end_cursor = html["data"]["user"]["edge_owner_to_timeline_media"]["page_info"]["end_cursor"]
edges = html["data"]["user"]["edge_owner_to_timeline_media"]["edges"]
for edge in edges:
click.echo(edge["node"]["display_url"])
count += 1
# all_imgs_url.append(edge["node"]["display_url"])
click.echo('ok')
except Exception as e:
raise e
if __name__ == '__main__':
crawl()
什么劳跃,你說怎么下載?那是下回的事情了浙垫,哈哈刨仑,相信有興趣的小伙伴早就是想法設(shè)法下載了。大家下回見哦夹姥,下回將整理整個代碼~~