本人比较喜欢段子,平时也经常上糗百。所以这次作业也想尝试一下爬取糗百的内容。
网站链接:https://www.qiushibaike.com/
主要想爬取的数据有段子内容、用户、投票数、评论数、热门评论等等。其实没有用什么特别的技巧,也没有什么反爬机制,所以比较简单,用xpath来进行定位获取相应的内容就行。
具体的步骤就不详细说明了,po上代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re
import json
import time
import requests
# import pymongo
from scrapy import Selector
class BaiKe():
def __init__(self):
# 初始化爬取条数
self.num = 0
# 实例化mongo client连接对象
# client = pymongo.MongoClient('127.0.0.1', 27017)
# self.coll = client['spider']['baike']
def get_item(self):
'''返回一个初始化后的item'''
item = {}
item['content'] = '' # 主要内容
item['id'] = '' # 唯一ID
item['person_name'] = '' # 用户名
item['age'] = '' # 年龄
item['gender'] = '' # 性别
item['comment_num'] = '' # 评论数
item['vote_num'] = '' # 投票数
item['hot_comment'] = '' # 热门评论
return item
def lie_biao(self, url):
'''获取列表信息'''
# 设置请求的头部信息,伪装成浏览器
headers = {
'Host': 'www.qiushibaike.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36',
}
# 使用get请求访问url,并带上头部信息
r = requests.get(url, headers=headers)
# 根据返回的网页信息生成一个选择器对象
body = Selector(text=r.text)
# 获取列表中的所有div标签,生成一个div选择器列表
divs = body.xpath('//div[@id="content-left"]/div')
# 循环列表
for div in divs:
item = self.get_item()
contents = div.xpath('a[@class="contentHerf"]/div/span/text()').extract()
# 将列表信息转换为字符串
content = '\n'.join(contents)
# 将内容放入到字典中
item['content'] = content
# 内容唯一ID
id = div.xpath('@id').extract()
if id:
data = re.search(r'\d+', id[0])
if data:
item['id'] = data.group()
# 用户名
person_name = div.xpath('div[@class="author clearfix"]/a[@title]/h2/text()').extract()
if person_name:
item['person_name'] = person_name[0]
# 年龄
age = div.xpath('div[@class="author clearfix"]/div/text()').extract()
if age:
item['age'] = age[0]
# 性别
gender_class = div.xpath('div[@class="author clearfix"]/div/@class').extract()
if gender_class:
if 'women' in gender_class[0]:
item['gender'] = u'女'
else:
item['gender'] = u'男'
# 进入详情页
detail_url = div.xpath('a[@class="contentHerf"]/@href').extract()
if detail_url:
url = 'https://www.qiushibaike.com' + detail_url[0]
self.get_detail(url, item)
# 分页
next = body.xpath('//ul[@class="pagination"]/li[last()]/a/span/text()').extract()
if next and next[0].strip() == u'下一页':
next_url = body.xpath('//ul[@class="pagination"]/li[last()]/a/@href').extract()[0]
next_url = 'https://www.qiushibaike.com' + next_url
self.lie_biao(next_url)
def get_detail(self, url, item):
'''获取详情信息'''
# 设置请求的头部信息,伪装成浏览器
headers = {
'Host': 'www.qiushibaike.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36',
}
# 使用get请求访问url,并带上头部信息
r = requests.get(url, headers=headers)
# 根据返回的网页信息生成一个选择器对象
body = Selector(text=r.text)
# 投票数
vote_num = body.xpath('//span[@class="stats-vote"]/i/text()').extract()
if vote_num:
item['vote_num'] = vote_num[0]
# 评论数
comment_num = body.xpath('//span[@class="stats-comments"]/i/text()').extract()
if comment_num:
item['comment_num'] = comment_num[0]
# 最热门的评论
hot_comment = body.xpath('//div[@class="comments-list-item"]/div[1]/a/div[@class="main-text"]/text()').extract()
if hot_comment:
item['hot_comment'] = hot_comment[0]
# 写入文件
self.write_file(item)
# 写入数据库
# self.write_mongo(item)
def write_file(self, item):
'''将item写入到文件中'''
# 将item字典转换为json字符串
json_str = '{}\n'.format(json.dumps(dict(item),ensure_ascii=False))
# 写入文件
with open('./baike_all.txt', 'a') as fp:
fp.write(str(json_str))
self.num += 1
print(u'已入库:', self.num, u'条。')
def write_mongo(self, item):
'''将item写入数据库中'''
self.coll.update({'id': item['id']}, {'$set': item}, upsert=True)
self.num += 1
print(u'已入库:', self.num, u'条。')
def run(self):
'''启动方法'''
url = 'https://www.qiushibaike.com/'
self.lie_biao(url)
def read_file(self):
'''文件的读取'''
with open('./baike.txt', 'r') as fp:
for line in fp.readlines():
item = json.loads(line)
print(item['content'])
print('*'*10)
# python文件会从这个if语句开始执行
if __name__ == '__main__':
# 实例化Baike类,生成bk实例
bk = BaiKe()
# 调用run方法
bk.run()
爬取的部分内容如下: