城市生活知识图谱 ②爬取百度贴吧之长沙吧


前言

上期说到我们爬取了长沙美食吧的一些帖子数据,但是发现有点问题。

  • 长沙美食吧基本上都是打广告的,都是培训广告,没几个活人
  • 数据量太小了,一台机器奋斗一天才几千条数据,这是远远不够的

为了解决上述问题,访问了长沙吧进行调查。

一、被抓

话说我回头想了想,数据爬取的慢的原因是因为每次翻页都需要点击完50个href链接才行,可是我需要的语料不就是长文本吗?标题已经给了,楼主说的内容,其实也展示了前200字,也就是说只要发帖人发布的内容不超过200字就不用点进去了。另外,其他人回复发帖人,会和问题有点关联,比如说某人发帖问哪里有好吃的,这个时候回复的人可能就是一个很好的答案。不过为了爬取速度,我还是决定不管了。那么现在的策略就是直接翻页了,速度是之前的50倍,一晚上一个小时就爬取了8000多条帖子。但是到了后面翻页翻不动了,总是给你弹回首页,可能又是被抓了吧!

在这里插入图片描述

二、源码

# -*- coding: UTF-8 -*-
"""
@狮子搏兔:2022/1/7
"""
import random
import time
import asyncio
import logging
import tkinter
import pandas as pd
from pyppeteer import launcher
import json
from bs4 import BeautifulSoup
from lxml import etree

launcher.DEFAULT_ARGS.remove("--enable-automation")  # 必须在 from pyppeteer import launch 去除浏览器自动化参数
from pyppeteer import launch


def get_existdata(path):
    with open(path, "r", encoding='utf-8') as f:
        data = json.loads(f.read())
    f.close()
    return data


def getherf(html):
    dic = {}
    bsobj = BeautifulSoup(html, 'html.parser')
    content = bsobj.find_all('a', attrs={'class': "j_th_tit"})
    intro = bsobj.find_all('div', attrs={'class': "threadlist_abs threadlist_abs_onlyline"})
    if intro:
        intro = [b.text for b in intro]
    href = []
    title = []

    if content:
        href = [b['href'] for b in content]
        title = [b.text for b in content]
    if href:
        if href[0] == '/p/7552843831' or href[0] == '/p/7460502035':
            title.pop(0)
            href.pop(0)
        if href[0] == '/p/7552843831' or href[0] == '/p/7460502035':
            title.pop(0)
            href.pop(0)

    if len(title) == len(intro) and len(title) == len(href):
        for i in range(len(title)):
            dic[href[i]] = {'title': title[i], 'intro': intro[i]}
    return dic


async def main():
    # 浏览器 启动参数
    start_parm = {
        # 启动chrome的路径
        "executablePath": r"C:\Program Files\Google\Chrome\Application\chrome.exe",
        # 关闭无头浏览器
        "headless": False,
        "args": [
            '--disable-infobars',  # 关闭自动化提示框
            '--window-size=1920,1080',  # 窗口大小
            '--log-level=30',  # 日志保存等级, 建议设置越好越好,要不然生成的日志占用的空间会很大 30为warning级别
            # '--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
            # UA
            '--no-sandbox',  # 关闭沙盒模式
            '--start-maximized',  # 窗口最大化模式
            # '--proxy-server=http://localhost:1080'  # 代理
            # r'userDataDir=D:\project_demo\python_demo\spider_demo\JavaScript 逆向系列课\userdata'  # 用户文件地址
        ],
    }

    browser = await launch(**start_parm)
    page = await browser.newPage()
    tk = tkinter.Tk()
    width = tk.winfo_screenwidth()
    height = tk.winfo_screenheight()
    tk.quit()

    await page.setViewport(viewport={'width': width, 'height': height})

    # 第二步,修改 navigator.webdriver检测
    # 其实各种网站的检测js是不一样的,这是比较通用的。有的网站会检测运行的电脑运行系统,cpu核心数量,鼠标运行轨迹等等。
    # 反爬js
    js_text = """
() =>{ 
    Object.defineProperties(navigator,{ webdriver:{ get: () => false } });
    window.navigator.chrome = { runtime: {},  };
    Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });
    Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5,6], });
 }
    """
    await page.evaluateOnNewDocument(js_text)  # 本页刷新后值不变,自动执行js
    headurl = 'https://tieba.baidu.com/'  # 内容url头部,用于拼接herf
    url = 'https://tieba.baidu.com/f?kw=%E9%95%BF%E6%B2%99&ie=utf-8&pn='  # 页数url头部
    existdata = get_existdata('data/csb_data.json')  # 读取目前有多少数据
    startpage = 15000
    num = len(existdata) // 50 * 50  # 计算应该跳到的页数
    num = startpage
    if num == 0:
        num += 50
    flag = True
    with open("data/newdata.json", "w", encoding='utf-8') as f:
        while num <= 988850:  # 最大为19780页,每页50条数据
            print('正在爬取第{}页'.format(num))
            await page.goto(url + str(num))  # 访问herf页面
            try:
                herftext = await page.content()  # 获取html
            except BaseException:
                continue
            contentdic = getherf(herftext)  # 获取50条帖子的标题以及intro
            if len(contentdic) > 0:
                dic = {}
                for k in contentdic:  # 去重
                    if k not in existdata:
                        dic[k] = contentdic[k]
                if len(dic) > 0:
                    f.write(json.dumps(dic, indent=0))  # 写入
            time.sleep(random.randint(2, 5))  # 随机等待,单位秒
            num += 50  # 翻页
    f.close()
    # await browser.close()


if "__main__" == __name__:
    asyncio.get_event_loop().run_until_complete(main())

总结

下面就要去找个好用点的命名实体识别标注的工具了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是狮子搏兔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值