今天我们下载头条的图片内容。
进入头条首页,我们根据关键词搜索。
发现有搜索出很多的条目,而且条目是根据鼠标往下滑动的时候就会动态加载出来,是动态更新的,之前我们曾使用过Selenium进行模拟鼠标滑动,一次性获得了很多的条目,最后再把所有页面的对应图片组的入口找出来,而今天我们试图用分析http request请求的方式来搞一次,每一次动态加载都是一次请求,所以我们来试图分析分析请求,看看能不能做出来。
每一个条目点击进去能看到相应的文章里面有很多图片,说明是一个图片组。
好了,看了大概的内容展示后,言归正传,我们进入正题。
首先我们得来分析下每一次动态加载得http请求,看看能不能找到什么item规律,于是打开开发者窗口,请按“F12”。然后不断下滑下滑进行动态加载,我们再network窗口进行观察。
如下:
我们连续请求四次,发现四次得请求在数据请求上很有规律。
每一次都是offset不一样,offset就是分页得偏移,count是每一次分页得总数,整个是保持不变,
每一次得timestamp和_signature也是不一样得,但是经过测试发现,这俩可以不用加上,也就是对于爬取数据来说没啥用处,可以忽略掉。
每一次请求后,得到的数据是:
每一个组图都有一个groupId,我们拿到这个ID后,打开json中的article_url,发现会跳转到另外一个地址,比如地址会从
输入:https:// toutiao.com/group/6887210541710836232/
跳转到:https://www.toutiao.com/a6887210541710836232/
这样我们通过groupid来拼装出组图的文章地址,使用Selenium来打开页面,找到所有的img,进行下载!
组图页面的每个图片的class都是 “syl-page-img”。嗯,这就不难了,不错!
好了整个过程就是这样的。现在给出完整代码:
import requests
from urllib.parse import urlencode
import time
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import os
from concurrent.futures import ThreadPoolExecutor
chromeExeLoc = 'D:/software/chrome/chromedriver_win32/chromedriver.exe'
rootrurl = 'https://www.toutiao.com/api/search/content/?'
ERROR_SELF_DEF = "ERROR"
save_dir = 'D:/estimages/'
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36",
'Accept-Language': 'en-US,en;q=0.8',
'Cache-Control': 'max-age=0',
'Connection': 'keep-alive'} # 伪装成浏览器
# 根据某个url和一堆参数去获得某个json数据
def request_url_data(url):
# 获得json数据
try:
resp = requests.get(url,headers=headers)
if resp.status_code == 200:
return resp.text
except requests.RequestException as e:
print('fail to get json data.')
return ERROR_SELF_DEF
def saveOneImg(dir, img_url):
new_headers = {
"Referer": img_url,
'User-Agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36",
'Accept-Language': 'en-US,en;q=0.8',
'Cache-Control': 'max-age=0',
'Connection': 'keep-alive'
} ###设置请求的头部,伪装成浏览器,实时换成新的 header 是为了防止403 http code问题,防止反盗链,
try:
img = requests.get(img_url, headers=new_headers) # 请求图片的实际URL
if (str(img).find('200') > 1):
with open(
'{}/{}.jpg'.format(dir, img_url.split('/')[-1].split('?')[0]), 'wb') as jpg: # 请求图片并写进去到本地文件
jpg.write(img.content)
print(img_url)
jpg.close()
return True
else:
return False
except Exception as e:
print('exception occurs: ' + img_url)
print(e)
return False
def downloadAllImgs(imgs, dir):
if not os.path.exists(dir):
os.makedirs(dir)
for img in imgs:
saveOneImg(dir, img.get_attribute('src'))
pass
# 再一个字符串s中找到所有的字串substr
def find_all(sub, s):
index_list = []
index = s.find(sub)
while index != -1:
index_list.append(index)
index = s.find(sub, index + 1)
if len(index_list) > 0:
return index_list
else:
return -1
# 得到所有的文章的groupId
def parseArticles(json):
json = json.replace(' ','')
li = find_all('"group_id"', json)
urls = []
for item in li:
beg = json.find(':', item)+2
# beg = json.find('http', item)
end = json.find(',', item)-1
urls.append(json[beg:end])
return urls
def searchKeyWord(offset, keyword, browser):
ts = str(time.time()).replace('.', '')[0:13]
params = {
'aid': 24,
'app_name': 'web_search',
'offset': offset,
'format': 'json',
'keyword': keyword,
'autoload': 'true',
'count': 20,
'en_qc': 1,
'cur_tab': 1,
'from': 'search_tab',
'pd': 'synthesis',
'timestamp': ts,
}
# 拼装url
url = rootrurl + urlencode(params)
# 通过url去异步请求json数据
json = request_url_data(url)
# 解析json然后得到所有的文章的groupId
groupIds = parseArticles(json)
for groupId in groupIds:
article = '{}{}/'.format('https://www.toutiao.com/a', groupId)
print(article)
browser.get(article) # get the
imgs = browser.find_elements_by_class_name('syl-page-img')
downloadAllImgs(imgs, '{}{}/{}'.format(save_dir, keyword, groupId))
def tagSpider(keyword):
# 无头浏览器 这样浏览器就不会弹出那个chrome的web浏览器界面
options = Options()
options.add_argument('--headless')
browser = webdriver.Chrome(chromeExeLoc)
browser.maximize_window()
browser.implicitly_wait(10)
# 别贪心,只抓取几次即可。
for offset in range(20, 100, 20):
print('start.............., offset=%s' % offset)
searchKeyWord(offset, keyword, browser)
print('end.................')
browser.close()
browser.quit()
if __name__ == '__main__':
# 获得所有标签
taglist = ['动漫', '街拍美女', '林珍娜', '火影忍者']
#
# 给每个标签配备一个线程
with ThreadPoolExecutor(max_workers=15) as t: # 创建一个最大容纳数量为20的线程池
for tag in taglist:
t.submit(tagSpider, tag)
# 单个连接测试下下
# tagSpider('三吉彩花')
# 等待所有线程都完成。
while 1:
print('-------------------')
time.sleep(1)
效果图如下: