212 lines
7.2 KiB
Python
212 lines
7.2 KiB
Python
import requests
|
||
import re
|
||
import json
|
||
from lxml import etree
|
||
import os
|
||
import threading
|
||
from queue import Queue
|
||
|
||
'''
|
||
Time:2020年6月16日18:40:20
|
||
By:Eg.
|
||
'''
|
||
|
||
|
||
'''
|
||
爬取weibo某话题下评论中的图片
|
||
https://m.weibo.cn/status/4489758501815678?
|
||
https://weibo.com/6524978930/IF9XHxJpF?type=repost#_rnd1588381011696
|
||
'''
|
||
|
||
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36'}
|
||
cookies = ''
|
||
#取消掉证书warning
|
||
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
|
||
|
||
def visitorlogin():
|
||
'''
|
||
visitorlogin
|
||
return cookies
|
||
'''
|
||
|
||
#-------游客登录1
|
||
url = 'https://passport.weibo.com/visitor/genvisitor'
|
||
data = {'cb':'gen_callback',
|
||
'fp':json.dumps({"os":"1",
|
||
"browser":"Chrome81,0,4044,129",
|
||
"fonts":"undefined",
|
||
"screenInfo":"1280*800*24",
|
||
"plugins":"Portable Document Format::internal-pdf-viewer::Chrome PDF Plugin|::mhjfbmdgcfjbbpaeojofohoefgiehjai::Chrome PDF Viewer|::internal-nacl-plugin::Native Client"
|
||
})
|
||
}
|
||
r = requests.post(url,data=data,headers=headers,verify=False)
|
||
text = re.findall('gen_callback\((.*?)\);',r.text)[0]
|
||
tid = json.loads(text)['data']['tid']
|
||
#-------游客登录2
|
||
params = {'a':'incarnate',
|
||
't':tid,
|
||
'cb':'cross_domain'
|
||
}
|
||
url = 'https://passport.weibo.com/visitor/visitor'
|
||
r = requests.get(url,params=params,headers=headers,verify=False)
|
||
text = re.findall('cross_domain\((.*?)\);',r.text)[0]
|
||
sub = json.loads(text)['data']['sub']
|
||
subp = json.loads(text)['data']['subp']
|
||
#-------游客登录3
|
||
url = 'https://login.sina.com.cn/visitor/visitor'
|
||
params = {'a':'crossdomain',
|
||
's':sub,
|
||
'sp':subp,
|
||
'cb':'return_back'
|
||
}
|
||
r = requests.get(url,params=params,headers=headers,verify=False)
|
||
return r.cookies.get_dict()
|
||
|
||
def base62_decode(string):
|
||
'''
|
||
来自万能的百度
|
||
'''
|
||
alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||
base = len(alphabet)
|
||
strlen = len(string)
|
||
num = 0
|
||
|
||
idx = 0
|
||
for char in string:
|
||
power = (strlen - (idx + 1))
|
||
num += alphabet.index(char) * (base ** power)
|
||
idx += 1
|
||
|
||
return num
|
||
|
||
def mid_to_url(midint):
|
||
'''
|
||
来自万能的百度
|
||
'''
|
||
|
||
url = midint
|
||
url = str(url)[::-1]
|
||
size = len(url) / 4 if len(url) % 4 == 0 else len(url) / 4 + 1
|
||
result = []
|
||
for i in range(int(size)):
|
||
s = url[i * 4: (i + 1) * 4][::-1]
|
||
s = str(base62_decode(str(s)))
|
||
s_len = len(s)
|
||
if i < size - 1 and s_len < 7:
|
||
s = (7 - s_len) * '0' + s
|
||
result.append(s)
|
||
result.reverse()
|
||
return int(''.join(result))
|
||
|
||
|
||
class Th(threading.Thread):
|
||
def __init__(self, queue):
|
||
threading.Thread.__init__(self)
|
||
self.__queue = queue
|
||
|
||
def run(self):
|
||
while True:
|
||
test = self.__queue.get()
|
||
saveimg(test[0],test[1],test[2])
|
||
self.__queue.task_done()
|
||
|
||
|
||
queue = Queue(20)#线程数
|
||
for i in range(queue.maxsize):
|
||
t = Th(queue)
|
||
t.setDaemon(True)
|
||
t.start()
|
||
|
||
def saveimg(weiboid,comment_id,img_url):
|
||
#print(img_url)
|
||
filename = '{}/{}{}'.format(weiboid,comment_id,os.path.basename(img_url))
|
||
if os.path.exists(filename) == False:
|
||
with open(filename,'wb') as f:
|
||
while True:
|
||
try:
|
||
r_img = requests.get(img_url,headers=headers,cookies=cookies,timeout=5)
|
||
except:
|
||
print('下载pic出错',img_url)
|
||
else:
|
||
if r_img.status_code == 200:
|
||
break
|
||
f.write(r_img.content)
|
||
|
||
|
||
def getweiboid(string):
|
||
'''
|
||
https://m.weibo.cn/status/4489758501815678? 这种直接出4489758501815678
|
||
https://m.weibo.cn/status/J5PjY66K0?
|
||
https://weibo.com/6524978930/IF9XHxJpF?type=repost#_rnd1588381011696 这种需要转换IF9XHxJpF
|
||
'''
|
||
|
||
if 'm.weibo' in string:
|
||
#目测都是16位
|
||
weiboid = re.findall('/(\d{16})',string)[0]
|
||
else:
|
||
weiboid = re.findall('/\d+/([A-Za-z0-9]*)',string)[0]
|
||
weiboid = mid_to_url(weiboid)
|
||
return weiboid
|
||
|
||
def spider(weibourl):
|
||
global cookies
|
||
|
||
weiboid = getweiboid(weibourl)
|
||
#时间排列api
|
||
url = 'https://weibo.com/aj/v6/comment/big?ajwvr=6&id={}&filter=all&from=singleWeiBo'.format(weiboid)
|
||
if os.path.exists(weiboid) == False:
|
||
os.makedirs(weiboid)
|
||
#循环获取每一页
|
||
while True:
|
||
print(url)
|
||
tt = True
|
||
retry = 0
|
||
#重试专用
|
||
while tt:
|
||
r = requests.get(url,headers=headers,cookies=cookies)
|
||
html = etree.HTML(json.loads(r.text)['data']['html'])
|
||
#单个评论div
|
||
for div in html.xpath('/html/body/div/div/div[@class="list_li S_line1 clearfix"]'):
|
||
comment_id = div.xpath('./@comment_id')[0]
|
||
#通常用这种来展示
|
||
for imgurl in div.xpath('./div/div/div/ul/li/img/@src'):
|
||
#替换thumb180字段来获取高清大图
|
||
img_url = 'https:' + imgurl.replace('thumb180','large')
|
||
print('piclink:',img_url)
|
||
#saveimg(weiboid,comment_id,img_url)
|
||
queue.put([weiboid,comment_id,img_url])
|
||
|
||
#有时候weibo会以这种方式展示,代表请求太快
|
||
#for imgurl in div.xpath('./div/div/a[@title="网页链接"]/@href'):
|
||
if len(div.xpath('./div/div/a[@title="网页链接"]/@href')) ==0:
|
||
tt = False
|
||
else:
|
||
cookies = visitorlogin()
|
||
retry = retry + 1
|
||
print('retry',retry)
|
||
|
||
|
||
#获取下一页地址
|
||
baseurl = 'https://weibo.com/aj/v6/comment/big?{}&from=singleWeiBo'
|
||
#'&from=singleWeiBo'不能去掉,不然会出现各种balabala问题
|
||
try:
|
||
url = baseurl.format(html.xpath('/html/body/div/div/div[@node-type="comment_loading"]/@action-data')[0])
|
||
except IndexError:
|
||
try:
|
||
url = baseurl.format(html.xpath('/html/body/div/div/div/div/a[@class="page next S_txt1 S_line1"]/span/@action-data')[0])
|
||
except IndexError:
|
||
try:
|
||
url = baseurl.format(html.xpath('/html/body/div/div/a[@action-type="click_more_comment"]/@action-data')[0])
|
||
except IndexError:
|
||
## with open('test.html','w',encoding='utf-8') as f:
|
||
## f.write(json.loads(r.text)['data']['html'])
|
||
break #没意外的话应该是已经获取完
|
||
cookies = visitorlogin()
|
||
|
||
if __name__ == '__main__':
|
||
cookies = visitorlogin()
|
||
print('cookies:',cookies)
|
||
spider('https://m.weibo.cn/detail/4511863448505629?')
|
||
# spider('https://m.weibo.cn/status/4489758501815678?')
|
||
queue.join()#等待下载完成
|