爬取今日头条图片
1. 引言
针对python爬虫—分析Ajax请求对json文件爬取今日头条街拍美图中存在的爬取图片为缩略图以及图片不全的问题,本文做出如下改进:
(1) 爬取网页全部的图片;
(2) 爬取原始图片;
(3) 将图片url存储到MySQL。
作者处于爬虫入门阶段,可能有些部分不是很准确,恳请各位批评指正。
2. 分析
2.1 获取主页的url
2.2 获取当前页所有文章的链接
上图是当前页所有文章的具体信息,共20条数据。
点开其中的一条,"article_url"即原文的url。
"image_list"中的数据只是对应网页的部分图片,并且为缩略图。所以我们要跳转到对应文章的url分析其中数据。
缩略图效果:
2.3 具体文章的信息
其中,在"pgc-img"下的"img_src"是原图的地址,所以我们要获取这些数据。
原始图像效果:
在获取img_src时,发现,采用requests.get(url).txt和BeautifulSoup等方法无法获取正确的img_src,所以采用selenium方法。
2.4 MySQL设置
创建数据库:JRTT,建表 data11,三个字段:
(1) id:int 20 主键 非空 自增
(2) title:varchar 100
(3) image:varchar 100
3.代码
# -*- codeing = utf-8 -*-
#@Time : 2020-12-11 13:19
#@Author : Guo
#@Fil : spider.py
#@Software : PyCharm
import json
import re
from urllib.parse import urlencode
import pymysql
from requests.exceptions import RequestException
import requests
from selenium import webdriver
import os
from hashlib import md5
headers = {
'referer': 'https://www.toutiao.com/search/?keyword=%E8%A1%97%E6%8B%8D',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
'x-requested-with': 'XMLHttpRequest'
}
def get_page_index(offset, keyword):
data = {
'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': '1607646692776',
'_signature': '_02B4Z6wo00f0195MhUAAAIBArYVsuw9LjmfeSYHAAKhKgV6P8VnGt8BgGfYqBzurBqNVSPjaCMcZ0577a6yeYsB1mU38awHzZTSOceC.rPC5xdL3o.MNfhlP4pPWgKCvXsqylAdmhUUfXHP52b'
}
url = 'https://www.toutiao.com/api/search/content/?' + urlencode(data)
try:
response = requests.get(url)
if response.status_code == 200:
return response.text
return None
except RequestException:
print("请求索引页失败")
return None
# 获取当前页所有文章的链接 article_url
def parse_page_index(html):
data = json.loads(html)
for item in data.get('data'):
if 'article_url' in item.keys() and item['article_url'] != []:
yield item.get('article_url')
# 具体访问每一个文章
def get_page_detail(url):
# option = webdriver.ChromeOptions()
# option.add_argument('headless') # 设置option
# browser = webdriver.Chrome(options=option) # 调用带参数的谷歌浏览器
browser = webdriver.Chrome()
browser.get(url)
html = browser.page_source
browser.close()
return html
# 解析详情页
def parse_page_detail(html):
title_pattern = re.compile('<title>(.*?)</title>')
images_pattern = re.compile('<div class="pgc-img">.*?<img src="(.*?)".*?>', re.S)
result_title = re.search(title_pattern, html).group(1)
result_images = re.findall(images_pattern,html)
if result_images and result_title:
for i in range(len(result_images)):
yield {
'title': result_title,
'image': result_images[i]
}
def get_conn():
conn = pymysql.connect(host="127.0.0.1",
user="root",
password="输入MySQL的密码",
db="JRTT")
cursor = conn.cursor()
return conn, cursor
def close_conn(conn, cursor):
cursor.close()
conn.commit()
conn.close()
def save_to_mysql(result):
conn, cursor = get_conn()
if result!= None:
a = [result.get('title'), result.get('image')]
sql = "insert into data11(title, image) values(%s,%s)"
cursor.execute(sql, (a[0], a[1]))
close_conn(conn, cursor)
def save_image(item):
if not os.path.exists(item.get('title')):#判断当前文件夹下是否有该文件
os.mkdir(item.get('title'))#如果不存在就创建该文件夹
try:
response = requests.get(item['image']) #get函数获取图片链接地址,requests发送访问请求,上面那个字典
if response.status_code==200: # 访问成功 进行下一步操作
file_path='{0}/{1}.{2}'.format(item.get('title'),md5(response.content).hexdigest(),'jpg')
# md5摘要算法(哈希算法),通过摘要算法得到一个长度固定的数据块。将文件保存时,通过哈希函数对每个文件进行文件名的自动生成。
# md5() 获取一个md5加密算法对象
# hexdigest() 获取加密后的16进制字符串
if not os.path.exists(file_path):
with open(file_path,'wb') as f:
f.write(response.content)
print('Downloaded image path is: ', file_path)
else:
print('Already Dowloaded',file_path)
except requests.ConnectionError:
print('Failed to Save Image')
def main():
for offest in range(0,20,20): # 定义爬取的范围
html = get_page_index(offest,"街拍")
for url in parse_page_index(html):
html = get_page_detail(url)
if html:
result = parse_page_detail(html)
for i in result:
save_image(i) # 保存到本地
save_to_mysql(i) # 保存到mysql
if __name__ == '__main__':
main()