爬虫练习(2)-- 使用正则匹配爬取果壳问答

分析

从 web 的角度来看,网站架构分为前后端分离和前后端不分离,如果是前后端不分离的结构,我们就需要从响应中去匹配我们希望提取的数据。举个例子就是 果壳网的热门问答。
这里写图片描述

获取整个网页

去正则匹配之前比较习惯先把代码跑通,我们可以尝试去构建出这样的结构,把当前的整个网页先打印出来,再去调试

# coding:utf-8
import requests

# <h2><a target="_blank" href="https://www.guokr.com/question/667020/">“三季人”是古文吗?</a></h2>
class Guoke(object):
    def __init__(self):
        self.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'
        }
        self.url = 'https://www.guokr.com/ask/hottest/'
        self.file = open('guoke.json', 'w')
        pass

    def get_data(self, url):
        response = requests.get(url, headers=self.headers)
        return response.content

    def parse_data(self, data):
        str_data = data.decode()
        print(str_data)

    def run(self):
        data = self.get_data(self.url)
        self.parse_data(data)

    def __del__(self):
        self.file.close()

if __name__ == "__main__":
    guoke = Guoke()
    guoke.run()

运行之后,我们可以发现我们已经获取了当前的完整的网页数据。

正则匹配果壳问题

我们想要匹配的的是 <h2><a target="_blank" href="https://www.guokr.com/question/667020/">“三季人”是古文吗?</a></h2>

正则的写法:<h2><a target="_blank" href="(.+?)">(.+?)</a></h2>
分别匹配链接和标题 其中? 表示非贪婪模式

修改 parse_data 方法,

    def parse_data(self, data):
        str_data = data.decode()
        res_list = re.findall('<h2><a target="_blank" href="(.+?)">(.+?)</a></h2>', str_data)
        print(res_list)

这次我们已经提取到当前页的所有问答的 url 和标题

    [('https://www.guokr.com/question/667020/', '“三季人”是古文吗?'), ('https://www.guokr.com/question/392570/', 'EVA Q的这张海报是银河的哪一段啊?'), ('https://www.guokr.com/question/677147/', '什么决定时间的流逝?物体内动能还是?'), ('https://www.guokr.com/question/582248/', '动漫制作有那些过程?'), ('https://www.guokr.com/question/537650/', '干虾为何有氨气味?'), ('https://www.guokr.com/question/676492/', '宝宝总是喜欢吃辣条怎么办?'), ('https://www.guokr.com/question/599265/', '精神病患者,怎样说服她去看医生?'), ('https://www.guokr.com/question/559078/', '用普通塑料袋装热的食物,比如粥什么的,到底有没有害?'), ('https://www.guokr.com/question/160920/', 'wifi信号会受什么的影响?'), ('https://www.guokr.com/question/492513/', '“死”字里为什么有个七夕?'), ('https://www.guokr.com/question/534950/', '科学青年如何写春联?'), ('https://www.guokr.com/question/516692/', '你认为最丑的公式有哪些?'), ('https://www.guokr.com/question/126413/', '有异地恋成功的吗?你们是怎么熬过来的?'), ('https://www.guokr.com/question/506176/', '你是如何理解创业的?'), ('https://www.guokr.com/question/542184/', '《西游记》里为什么把唐僧描写的那么无能?'), ('https://www.guokr.com/question/203569/', '二战美军的降落伞质检的传说是真的吗?'), ('https://www.guokr.com/question/676930/', '未来的果壳还有可能东山再起吗?'), ('https://www.guokr.com/question/628160/', '青蛙能认识自己生的宝宝嘛?'), ('https://www.guokr.com/question/545625/', '咖啡真的能降低自杀率吗?'), ('https://www.guokr.com/question/669761/', '印度人把男人的生殖器叫林伽,把女人的生殖器叫瑜尼,林伽和瑜尼的交合,便是瑜伽。这是真还是假的')]

保存为 json 格式的数据

修改parse_data方法,将元组中的数据组合为字典,再添加到一个字典列表里面:

def parse_data(self, data):
        str_data = data.decode()
        print(str_data)
        res_list = re.findall('<h2><a target="_blank" href="(.+?)">(.+?)</a></h2>', str_data)

        temp_list = []
        for res in res_list:
            temp_dict = {}
            temp_dict["url"] = res[0]
            temp_dict["title"] = res[1]
            temp_list.append(temp_dict)

        print(temp_list)
        return temp_list

同时定义出数据的保存方法, save_data

def save_data(self, data_list):
        for data in data_list:
            str_data = json.dumps(data, ensure_ascii=False) + ',\n'
            self.file.write(str_data)

guoke.json 文件

{"title": "“三季人”是古文吗?", "url": "https://www.guokr.com/question/667020/"},
{"title": "EVA Q的这张海报是银河的哪一段啊?", "url": "https://www.guokr.com/question/392570/"},
{"title": "什么决定时间的流逝?物体内动能还是?", "url": "https://www.guokr.com/question/677147/"},
{"title": "动漫制作有那些过程?", "url": "https://www.guokr.com/question/582248/"},
{"title": "干虾为何有氨气味?", "url": "https://www.guokr.com/question/537650/"},
{"title": "宝宝总是喜欢吃辣条怎么办?", "url": "https://www.guokr.com/question/676492/"},
{"title": "精神病患者,怎样说服她去看医生?", "url": "https://www.guokr.com/question/599265/"},
{"title": "用普通塑料袋装热的食物,比如粥什么的,到底有没有害?", "url": "https://www.guokr.com/question/559078/"},
{"title": "wifi信号会受什么的影响?", "url": "https://www.guokr.com/question/160920/"},
{"title": "“死”字里为什么有个七夕?", "url": "https://www.guokr.com/question/492513/"},
{"title": "科学青年如何写春联?", "url": "https://www.guokr.com/question/534950/"},
{"title": "你认为最丑的公式有哪些?", "url": "https://www.guokr.com/question/516692/"},
{"title": "有异地恋成功的吗?你们是怎么熬过来的?", "url": "https://www.guokr.com/question/126413/"},
{"title": "你是如何理解创业的?", "url": "https://www.guokr.com/question/506176/"},
{"title": "《西游记》里为什么把唐僧描写的那么无能?", "url": "https://www.guokr.com/question/542184/"},
{"title": "二战美军的降落伞质检的传说是真的吗?", "url": "https://www.guokr.com/question/203569/"},
{"title": "未来的果壳还有可能东山再起吗?", "url": "https://www.guokr.com/question/676930/"},
{"title": "青蛙能认识自己生的宝宝嘛?", "url": "https://www.guokr.com/question/628160/"},
{"title": "咖啡真的能降低自杀率吗?", "url": "https://www.guokr.com/question/545625/"},
{"title": "印度人把男人的生殖器叫林伽,把女人的生殖器叫瑜尼,林伽和瑜尼的交合,便是瑜伽。这是真还是假的", "url": "https://www.guokr.com/question/669761/"},

貌似 ip 被封了 … 一直504 …
过段时间接着写 …

扫描二维码关注公众号,回复: 2915949 查看本文章

恢复了,换代理也不行,当时应该正好是是服务器挂了 …

实现翻页

回忆联系1里面,我们实现翻页是去更改 ajax 请求的参数。对于数据和 url 在源码中的形式,思路是找到“下一页”对应的 url 然后再去请求这个 url ,循环上述的过程 …
代码如下 :

# coding:utf-8
import requests
import re
import json

class Guoke(object):
    def __init__(self):
        self.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'
        }
        self.proxies = {
            'http':"http://183.163.40.223:31773",
        }

        self.url = 'https://www.guokr.com/ask/hottest/'
        self.file = open('guoke.json', 'w')

    def get_data(self, url):
        response = requests.get(url, proxies=self.proxies, headers=self.headers)
        print(response.status_code)
        # print(response.content)
        return response.content

    def parse_data(self, data):
        str_data = data.decode()
        print(str_data)
        res_list = re.findall('<h2><a target="_blank" href="(.+?)">(.+?)</a></h2>', str_data)

        temp_list = []
        for res in res_list:
            temp_dict = {}
            temp_dict["url"] = res[0]
            temp_dict["title"] = res[1]
            temp_list.append(temp_dict)

        # 匹配 "下一页" 对应的 url
        # <a href="/ask/hottest/?page=2">下一页</a>
        next_url = re.findall('<a href="(/ask/hottest/\?page=\d+)">下一页</a>', str_data)
        # print(next_url)
        # print(temp_list)
        if next_url:
            next_url = 'https://www.guokr.com' + next_url[0]
        return temp_list, next_url

    def save_data(self, data_list):
        for data in data_list:
            str_data = json.dumps(data, ensure_ascii=False) + ',\n'
            self.file.write(str_data)

    def run(self):
        while True:
            data = self.get_data(self.url)
            data_list, next_url = self.parse_data(data)
            self.save_data(data_list)
            self.url = next_url
            if not next_url:
                break

    def __del__(self):
        self.file.close()

if __name__ == "__main__":
    guoke = Guoke()
    guoke.run()

查看json文件一共爬取了 64条数据 … 跟网页上的 4 页 64条数据一致 ….

联系方式

qq:2564493603
欢迎交流

猜你喜欢

转载自blog.csdn.net/Enjolras_fuu/article/details/81278282