我们首先打开今日头条,搜索“罗志祥”
打开浏览器的开发者工具,红色框中就是我们请求到的数据
将搜索界面的滚动条滑到底,在开发者工具中就可以看到所有请求到的数据,加上前面的一条,一共是7条数据。同时还发现每条数据的偏移量offset为20,因此我们在构造链接请求数据时,只需要改变offset即可。
点开第一条数据,可以看到请求链接的格式,后面我们需要构造参数来生成链接。
为了保证爬虫的稳定性(爬取过程中可能会有验证码),我们要在请求头中加入如下参数。
现在点开第一条数据,可以看到data中就是有关每篇文章的一些数据信息,我们要提取包含文章链接article_url的项。
但是我们可以看到,上张图中的文章链接不是今日头条站内的,而是今日头条转载其他网站的文章,而不同的网站结构也不同,不好解析,因此这里我们只爬取今日头条网站内的文章。
打开文章链接,可以看到文章的内容。
查看网页源代码,可以看到网页使用js渲染的,我们直接使用正则表达式匹配提取文章内容。
爬取思路:
(1)导入包,构造请求头
import os
import re
import csv
import time
import html
import requests
from urllib.parse import urlencode
headers = {
'cookie': 'tt_webid=6803226732523800077; WEATHER_CITY=%E5%8C%97%E4%BA%AC; tt_webid=6803226732523800077; csrftoken=001c46806c4ddb1c2b0ef69c22890fcf; ttcid=8b695caa90e6433593bc380c6169f17d27; SLARDAR_WEB_ID=5d5ed608-2dda-4d11-b7ed-238121ba5d44; s_v_web_id=verify_k9gguslb_rEU3y1j3_1Egi_4MUX_BRpa_ppngg9dAp1Op; __tasessionId=gjkq6pqc01587870093173; tt_scid=FiyB9z79VVOWXzxX3rQkVUFrbT.kY47exuDy8fdctQueSFw42.wM3KgKWTxahUmG56f2',
'referer': 'https://www.toutiao.com/search/?keyword=%E7%BD%97%E5%BF%97%E7%A5%A5',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36',
'x-requested-with': 'XMLHttpRequest'
}
(2)请求一条Ajax数据
def get_one_page(offset):
params = {
'aid': '24',
'app_name': 'web_search',
'offset': offset,
'format': 'json',
'keyword': '罗志祥',
'autoload': 'true',
'count': 20,
'en_qc': 1,
'cur_tab': 1,
'from': 'search_tab',
'pd': 'synthesis',
'timestamp': int(time.time())
}
url = 'https://www.toutiao.com/api/search/content/?' + urlencode(params)
try:
response = requests.get(url, headers=headers)
if response.status_code == 200:
return response.json()
except requests.ConnectionError:
return None
(3)获取文章链接
def get_article_url(json):
if json['count'] != 0: #请求的文章数据不为0
for item in json['data']: #遍历每条文章
if 'article_url' in item: #如果存在文章链接
title = item['title'] #文章标题
publish_time = item['publish_time'] #发布时间戳
datetime = item['datetime'] #发布日期
abstract = item['abstract'] #摘要
article_url = item['article_url'] #文章链接
yield{
'title': title,
'publish_time': publish_time,
'datetime': datetime,
'abstract': abstract,
'article_url': article_url
}
(4)解析文章
def parse_article(article_url):
response = requests.get(article_url, headers=headers) #请求文章
if response.status_code == 200: #响应正常
try:
data = response.content.decode('utf-8')
text = re.findall(r"content:(.+)", data)[0] #正则匹配
text = html.unescape(text) #html转义
text = re.findall(r"'(.+)'", text)[0]
except:
text = None
if text: #替换无效字符
replace_list = [r'\\u003C', r'\\u003E', r'\\u002F', r'p', r'strong', r'p', r'br', r'div (.*?)div']
for replace in replace_list:
text = re.sub(replace, '', text)
return text
(5)保存文章内容
def save_article(content, text):
if not os.path.exists('articles/'):
os.mkdir('articles/')
file_path = 'articles/{0}.{1}'.format(content['title'], 'txt')
if not os.path.exists(file_path): #txt
with open(file_path, 'w', encoding='utf-8') as f:
f.write(text)
with open('articles/articles_table.csv', 'a', encoding='utf-8', newline='') as f:
w = csv.writer(f) #csv
w.writerow([content['title'],content['publish_time'],content['datetime'],content['abstract'],content['article_url'],text])
(6)主函数
def main(offset):
json = get_one_page(offset)
for item in get_article_url(json):
try:
article_url = item['article_url']
text = parse_article(article_url)
if text:
save_article(item, text)
except FileExistsError and OSError:
continue
(7)运行
if __name__ == '__main__':
for i in range(0,7):
main(i * 20)
print('爬取完成')
分析一下文章主要在说些什么。
import csv
import matplotlib.pyplot as plt
import jieba
from wordcloud import WordCloud
#1.读出
text = ''
csv_file = csv.reader(open('articles/articles_table.csv',encoding='utf-8'))
for row in csv_file:
text = text + row[-1]
#2.剪开
cut_text = jieba.cut(text)
stopwords = {'可以','已经','这些','虽然','如果','img','class','handler',
'不是','怎么','甚至','时候','没有','什么','大家','自己'}
cuttext = [i for i in cut_text if i not in stopwords]
#3.以空格拼接起来
result = " ".join(cuttext)
#生成词云
wc = WordCloud(
font_path='C:/Windows/fonts/simhei.ttf', #字体路径
background_color='white', #背景颜色
width=1000,
height=600,
max_font_size=50, #字体大小
min_font_size=10,
mask=plt.imread('bg.jpg'), #背景图片
max_words=1000
)
wc.generate(result)
wc.to_file('wordcloud.png') #图片保存