Scrapy 爬取百度贴吧指定帖子的发帖人和回帖人

转载请注明出处:http://blog.csdn.net/gamer_gyt
博主微博:http://weibo.com/234654758
Github:https://github.com/thinkgamer

前言

该篇文章将是Scrapy爬虫系列的开篇,随后会不定时更新该框架方面的内容和知识,在scrapy之前写爬虫主要用的BeautifulSoup, request 和urllib,但随着使用程度的加深,慢慢意识到功能和效率都是不够的,那么便重新接触了Scrapy框架,并尝试着写出一些有趣的东西。

什么是Scrapy

它是一个应用程序框架,用来抓取并提取网站中的结构化数据,在数据挖掘,信息处理等方面十分有用。

安装

pip install Scrapy

它是一个python包,依赖于以下几个python包

  • lxml : XML和HTML解析
  • parsel :基于lxml的HTML/XML解析器
  • w3lib :处理网页编码和URL解析器
  • twisted :一个异步网络框架
  • cryptography and pyOpenSSL :处理各种网络级安全需求

创建一个简单的项目

scrapy startproject tiebaSpider

目录结构为

tiebaSpider/
    scrapy.cfg            # 配置文件

    tiebaSpider/             # py 模块
        __init__.py

        items.py          # 定义一些数据模型文件

        pipelines.py      # 管道,用来进行数据的保存

        settings.py       # 关于项目的一些配置

        spiders/          # 该目录下编写自己的代码逻辑
            __init__.py

在soiders/下新建一个tibe.py文件,内容为:

# coding: utf-8

import scrapy

class TiebaSpider(scrapy.Spider):
    name = "tiebaSpider"

    def start_requests(self):
        urls = [
            'https://tieba.baidu.com/f?kw=%E6%88%92%E8%B5%8C&ie=utf-8&pn=0'
        ]

        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self,response):
        page = response.url.split("pn=")[1]
        filename = "tieba-%s.html" % page
        with open(filename, 'wb') as f:
            f.write(response.body)
        self.log('Saved file %s' % filename)
  • name: 爬虫名字
  • start_requests: 返回一个可迭代的请求地址
  • parse: 解析网页的函数
  • yield:python 生成器

运行爬虫:

scrapy crawl tiebaSpider

这里我们也可以这样写

# coding: utf-8

import scrapy

class TiebaSpider(scrapy.Spider):

	name = "tiebaSpider"

	start_urls = [
	    'https://tieba.baidu.com/f?kw=%E6%88%92%E8%B5%8C&ie=utf-8&pn=0',
	    ]
	def parse(self,response):
		page = response.url.split("pn=")[1]
		filename = "tieba-%s.html" % page
		with open(filename, 'wb') as f:
			f.write(response.body)
		self.log('Saved file %s' % filename)

因为parse是scrapy的默认回调函数,当然如果你要写好几自己定义的函数的话,就必须要指定自己的回调函数。

爬取贴吧用户

背景

爬取贴吧的尽可能多的用户名,作为推广使用(暂时使用以下的方法来获取用户名,后续会更新一种新的方法:对于给定的贴吧名,爬取其前三页所有帖子的发帖人和回帖人,这里只保存用户名)

分析

这里的实现思路是search 出来指定的贴吧,然后获取所有贴吧前三页的帖子 href,然后保存到文件中,再启用另外一个爬虫逐个帖子去爬取解析用户名

代码结构

tieba
  data
  tieba
    spiders
      __init__.py
      tieba1.py     # 获取所有的帖子的链接
      tieba2.py     # 获取发帖人和回帖人的用户名
    __init__.py
    items.py
    middlewares.py
    pipelines.py
    settings.py
  name.txt           #存放贴吧名
  scrapy.cfg

代码实现

tieba1.py

# coding: utf-8

import scrapy
import urllib
import time


class TiebaSpider(scrapy.Spider):

    name = 'tieba'

    def __init__(self):
        self.urls = []

        # 加载贴吧名
        fr = open("name.txt", "r")

        for one in fr.readlines():
            for i in range(0, 3):
                self.urls.append('https://tieba.baidu.com/f?kw=' +
                                 urllib.quote(one.strip()) + '&ie=utf-8&pn=' + str(i * 50))
        fr.close()

    def start_requests(self):
        urls = self.urls

        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        sel = scrapy.Selector(response)
        ahref_list = sel.xpath(
            '//a[re:test(@class, "j_th_tit ")]//@href').extract()

        fw = open("data/%s_all_href.txt" % time.strftime('%Y%m%d'), "a")
        for ahref in ahref_list:
            href = "https://tieba.baidu.com" + ahref
            fw.write(href + "\n")
        fw.close()

tieba2.py

# coding: utf-8

import scrapy
import time
from scrapy.http.request import Request
from scrapy.http import HtmlResponse

class TiebaSpider2(scrapy.Spider):

    name = 'tieba2'

    def __init__(self):
        self.urls = []

        # 加载贴吧名
        fr = open("data/%s_all_href.txt" % time.strftime('%Y%m%d'), "r")

        for one in fr.readlines():
            self.urls.append(one.strip())
        fr.close()

    def start_requests(self):
        urls = self.urls

        for one in urls:
            yield scrapy.Request(url=one, callback=self.parse)
    
    def parse_uname(self, response):
        # response = HtmlResponse(url=page_url.url)
        sel = scrapy.Selector(response)
        name_list = sel.xpath('//li[re:test(@class, "d_name")]//a/text()').extract()
        # print respons        
        fw = open("data/%s_all_name.txt" % time.strftime('%Y%m%d'), "a")
        for name in list(set(name_list)):
            fw.write(name.encode("utf-8"))
            fw.write("\n")
        fw.close()
    
    def parse(self, response):
        sel = scrapy.Selector(response)

        # 可能有些帖子被删除
        try:
            # 得到每个帖子有多少页
            num = int(sel.xpath('//span[re:test(@class,"red")]//text()').extract()[1])   
            # 遍历每页获得用户名
            for page_num in range(1, num + 1):
                one_url = response.url + "?pn=" + str(page_num)

                yield Request(url=one_url, callback=self.parse_uname) 
        except Exception as e:
            pass

代码的github地址为:点击查看

总结

相比BeautifulSoup ,urllib,request来讲,Scrapy更加的快捷,高效和灵活,而且使用lxml,parsel 来进行网页内容的解析比BS也更快


【技术服务】,详情点击查看: https://mp.weixin.qq.com/s/PtX9ukKRBmazAWARprGIAg

扫一扫 关注微信公众号!号主 专注于搜索和推荐系统,尝试使用算法去更好的服务于用户,包括但不局限于机器学习,深度学习,强化学习,自然语言理解,知识图谱,还不定时分享技术,资料,思考等文章!


  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值