首发于 Python爬虫-从入门到入职
Python爬虫入门到入职05:抓包与请求分析

Python爬虫入门到入职05:抓包与请求分析

大型项目中需要面对各式复杂的网络请求,所以抓包与请求分析是爬虫工程师的必备技能,需要熟练掌握。

本章知识点:

认识反爬虫

本章以 虎嗅网作为项目,根据之前的学习写出首页抓取代码:

运行爬虫,获得html源码:

很明显这个源码有问题,在chrome上按Ctrl+u,真正的源码长这样:



仔细查看错误源码,发现500 Internal Server Error字样。

查询 百度百科-HTTP状态码,500状态码表示:服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。

但是在chrome上刷新网页又能正常访问,那只能是程序发出的请求有问题,我们来做个验证:

对比结果,发现少了很多参数,而且“User-Agent”参数标识出我们是用python的requests库发送请求。

虎嗅网接收到请求,发现这人不是通过正常的浏览器进行访问,心想:他肯定是个爬虫,又来抓取我们网站的数据,返回一个错误页面给他得了。


这种通过请求头信息(如:headers中的User-Agent参数)屏蔽爬虫请求的方法,是网站最常用、最基础的反爬虫策略。


应对这种情况需要伪造请求,把所有参数设置得跟浏览器一样,我们来抓包查看chrome中的请求参数:

使用chrome开发者工具抓包

按下F12进入开发者工具页面,点击Network标签,刷新页面获得请求,如图:



点击首页链接对应的请求,显示出该请求的详细参数:



Request Headers部分就是请求头信息,按照chrome的抓包结果来伪造我们自己的请求:

成功获得正确的html源码,这里有两点需要注意:

继续修改代码,抓取第一页新闻:

class HuXiuSpider:
    def __init__(self):
        client = MongoClient(host='127.0.0.1', port=27017)
        self.coll = client.get_database('spider').get_collection('huxiu')

        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'}

    def start(self):
        self.crawl_index(1)

    def crawl_index(self, page):
        url = 'https://www.huxiu.com/'
        rsp = requests.get(url, headers=self.headers)
        soup = BeautifulSoup(rsp.text, 'lxml')
        for h2_node in soup.find('div', class_='mod-info-flow').find_all('h2'):
            href = h2_node.find('a')['href']
            url_news = urljoin(rsp.url, href)
            self.crawl_detail(url_news)

    def crawl_detail(self, url):
        rsp = requests.get(url, headers=self.headers)
        soup = BeautifulSoup(rsp.text, 'lxml')
        title = soup.find('div', class_='article-wrap').find('h1', class_='t-h1').text.strip()
        author = soup.find('span', class_='author-name').text.strip()
        try:
            publish_time = soup.find('span', class_='article-time pull-left').text.strip()
            collect = soup.find('span', class_='article-share pull-left').text.strip()
            comment = soup.find('span', class_='article-pl pull-left').text.strip()
            category = soup.find('a', class_='column-link').text.strip()
        except AttributeError:
            # 解析不同页面结构
            publish_time = soup.find('span', class_='article-time').text.strip()
            collect = soup.find('span', class_='article-share').text.strip()
            comment = soup.find('span', class_='article-pl').text.strip()
            category = ''
        article = soup.find('div', class_='article-content-wrap').text.strip()
        images = []
        images.append(soup.find('div', class_='article-img-box').find('img')['src'])  # 文章头图
        for img_node in soup.find('div', class_='article-content-wrap').find_all('img'):
            images.append(img_node['src'])

        data = {
            'title': title,
            'author': author,
            'publish_time': publish_time,
            'collect': collect,
            'comment': comment,
            'category': category,
            'article': article,
            'images': images,
            'url': url
        }
        print(data)

成功抓取网页源码。

请求分析

我们来进行翻页操作,虎嗅网的翻页有点另类:



网站使用ajax异步加载下一页数据,需要抓包获取请求详情:进入Network标签,清空之前的请求,点击“加载更多”按钮,查看请求参数:



分析请求:

根据抓包分析的结果改写代码:

import requests
from pymongo import MongoClient
from bs4 import BeautifulSoup
from urllib.parse import urljoin
import re
import time


class HuXiuSpider:
    def __init__(self):
        client = MongoClient(host='127.0.0.1', port=27017)
        self.coll = client.get_database('spider').get_collection('huxiu')
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'}

    def start(self):
        try:
            url = 'https://www.huxiu.com/'
            rsp = requests.get(url, headers=self.headers)
            soup = BeautifulSoup(rsp.text, 'lxml')
            for h2_node in soup.find('div', class_='mod-info-flow').find_all('h2'):
                href = h2_node.find('a')['href']
                url_news = urljoin(rsp.url, href)
                self.crawl_detail(url_news)

            # 使用正则表达式匹配字符串,(.*?)就是想要匹配的部分,带上问号表示只匹配一次
            regex_res = re.findall(r'huxiu_hash_code=\'(.*?)\'', rsp.text)
            if regex_res is not None:
                self.hash_code = regex_res[0]
                self.crawl_index_ajax(2)
        except:
            pass

    def crawl_index_ajax(self, page):
        try:
            req_data = {
                'huxiu_hash_code': self.hash_code,
                'page': page,
                'last_dateline': int(time.time()),  # 10位时间戳。以后看到15开头、10位或13位整数,就要注意这是不是时间戳
            }
            url = 'https://www.huxiu.com/v2_action/article_list'
            rsp = requests.post(url=url, data=req_data, headers=self.headers)  # 发送post请求,带上表单数据
            html = rsp.json()['data']  # requsts返回的对象内置了json()函数,可以方便的转成字典
            soup = BeautifulSoup(html, 'lxml')
            for h2_node in soup.find_all('h2'):
                href = h2_node.find('a')['href']
                url_news = urljoin(rsp.url, href)
                self.crawl_detail(url_news)

            if page == 2:
                # 这里可以拿到total_page进行分页
                max_page = int(rsp.json()['total_page'])
                for new_page in range(3, max_page + 1):
                    self.crawl_index_ajax(new_page)
        except:
            pass

    def crawl_detail(self, url):
        try:
            rsp = requests.get(url, headers=self.headers)
            soup = BeautifulSoup(rsp.text, 'lxml')
            title = soup.find('div', class_='article-wrap').find('h1', class_='t-h1').text.strip()
            author = soup.find('span', class_='author-name').text.strip()
            try:
                publish_time = soup.find('span', class_='article-time pull-left').text.strip()
                collect = soup.find('span', class_='article-share pull-left').text.strip()
                comment = soup.find('span', class_='article-pl pull-left').text.strip()
                category = soup.find('a', class_='column-link').text.strip()
            except AttributeError:
                # 解析不同页面结构
                publish_time = soup.find('span', class_='article-time').text.strip()
                collect = soup.find('span', class_='article-share').text.strip()
                comment = soup.find('span', class_='article-pl').text.strip()
                category = ''
            article = soup.find('div', class_='article-content-wrap').text.strip()
            images = []
            images.append(soup.find('div', class_='article-img-box').find('img')['src'])  # 文章头图
            for img_node in soup.find('div', class_='article-content-wrap').find_all('img'):
                images.append(img_node['src'])

            data = {
                'title': title,
                'author': author,
                'publish_time': publish_time,
                'collect': collect,
                'comment': comment,
                'category': category,
                'article': article,
                'images': images,
                'url': url
            }

            self.coll.insert_one(data)
            print(data)
        except:
            pass


if __name__ == '__main__':
    HuXiuSpider().start()

正则表达式

正则表达式是用于处理字符串的强大工具,本教程不单独讲解。

推荐教程: Python正则表达式指南

语法不用死记硬背,写写demo做到基本了解,遇到相关问题再来查询即可。


课外练习:

  1. 小饭桌:全量采集,写入mongodb

练习答案:

Github地址


下一章 >> Python爬虫入门到入职06:爬虫快跑!(努力写作中。。。)

深圳SEO优化公司天水网页设计哪家好新余网页设计沈阳模板网站建设呼和浩特网站建设设计报价本溪网站定制公司哈密关键词按天计费推荐仙桃企业网站设计柳州至尊标王价格吉安网站定制哪家好唐山SEO按天计费公司海口seo多少钱楚雄SEO按效果付费报价嘉兴建设网站多少钱青岛关键词按天收费多少钱百色seo网站推广恩施至尊标王公司阿坝网站优化推广多少钱莆田品牌网站设计推荐吉祥建设网站公司揭阳网站设计推荐青岛seo网站推广报价镇江百度关键词包年推广哪家好太原关键词按天收费报价玉溪网站优化软件报价南京企业网站改版公司扬州优化榆林seo排名安阳网站制作公司迁安网站定制价格濮阳SEO按天收费哪家好歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化