[爬虫笔记01] Ajax爬取今日头条文章

1.爬取分析

我们首先打开今日头条,搜索“罗志祥”
在这里插入图片描述
打开浏览器的开发者工具,红色框中就是我们请求到的数据
在这里插入图片描述
将搜索界面的滚动条滑到底,在开发者工具中就可以看到所有请求到的数据,加上前面的一条,一共是7条数据。同时还发现每条数据的偏移量offset为20,因此我们在构造链接请求数据时,只需要改变offset即可。
在这里插入图片描述
点开第一条数据,可以看到请求链接的格式,后面我们需要构造参数来生成链接。
在这里插入图片描述
为了保证爬虫的稳定性(爬取过程中可能会有验证码),我们要在请求头中加入如下参数。
在这里插入图片描述
现在点开第一条数据,可以看到data中就是有关每篇文章的一些数据信息,我们要提取包含文章链接article_url的项。
在这里插入图片描述
但是我们可以看到,上张图中的文章链接不是今日头条站内的,而是今日头条转载其他网站的文章,而不同的网站结构也不同,不好解析,因此这里我们只爬取今日头条网站内的文章。
在这里插入图片描述
打开文章链接,可以看到文章的内容。
在这里插入图片描述
查看网页源代码,可以看到网页使用js渲染的,我们直接使用正则表达式匹配提取文章内容。
在这里插入图片描述
爬取思路:

  1. 请求Ajax数据
  2. 获取文章url
  3. 请求文章网页
  4. 正则提取文章正文内容
  5. 保存文章数据
  6. 循环爬取

2.代码实现

(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('爬取完成')

(8)爬取结果
在这里插入图片描述
在这里插入图片描述

3.制作词云图

分析一下文章主要在说些什么。

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') #图片保存

在这里插入图片描述

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值