爬虫相信大家都有所了解,我对爬虫就不做详细介绍了。本次我决定使用scrapy爬取CSDN论坛发布的问题以及回答的内容。
首先,我们需要创建一个scrapy项目。
scrapy startproject test1
然后进入scrapy项目中,创建一个爬虫。
#进入scrapy项目中
cd test1
#创建爬虫
scrapy genspider csdn_spider bbs.csdn.net
创建爬虫时,前两个参数是固定的,第三个参数是你要创建的爬虫文件的名字,第四个参数是你要爬取的网站的网址,此处我们先随便写上一个。四个参数缺一不可。
接下来我们打开我们的项目,找到spider文件夹中我们刚创建的 'csdn_spider.py'文件。下面我们就要开始我们的爬虫项目了。
先对CSDN论坛进行分析,我们发现论坛的分页是比较简单的,每一页的网址只有特定地方的数字变了一下。所以我们可以创建一个函数对论坛每一页的url进行拼接。
#拼接url
def joint_url(url):
# for i in range(1,101):
#此处范围可以先改小点进行测试,测试成功后可以再进行增大范围的操作。
return [url.format(i) for i in range(1,10)]
下面分析每一个问题的url。我们会发现每个问题的url是这样的。
<a href="/topics/392451197" class="topic_title" target="_blank" title="关于读取EXCEL出现乱码的问题">关于读取EXCEL出现乱码的问题</a>
这个超链接是不完整的,所以我们需要再写一个函数拼接问题的url。
#拼接各个问题的url
def question_url(url):
#筛选出符合条件的url(只有满足条件的才是问题的url)
if '/topics' in url:
return "https://bbs.csdn.net"+url
else:
return None
网址都得到了,那么下面就可以爬取网页,并分析网页中我们想要得到的内容了。
下面就开始爬虫的整个流程。
首先,确定要爬取的种子网页。
因为我们设定了url拼接,所以我们的种子网页是多个,这里展示一下。
#导入类库
import scrapy
from scrapy import Request
class CsdnspiderSpider(scrapy.Spider):
#爬虫名字,用来启动爬虫
name = 'csdn_spider'
#过滤掉不满足条件的网址
allowed_domains = ['bbs.csdn.net']
def __init__(self):
#种子网址,与上面定义的拼接函数搭配使用。
self.urls = 'https://bbs.csdn.net/forums/OL_Script?page={}'
此处函数名必须是start_requests
def start_requests(self):
#循环访问每一页
for url_str in joint_url(self.urls):
#迭代器,参数1:访问网站url,参数2:回调函数,函数名必须是parse
yield Request(url=url_str,callback=self.parse)
获得返回的网页内容后,对内容进行筛选
#此处函数名必须是parse
def parse(self, response):
"""
提取每一页中的问题
:param response:
:return:
"""
#使用xpath,匹配出问题的链接
all_title_urls = response.xpath('//td[@class="forums_topic"]/a/@href').extract()
for one_title in all_title_urls:
#完整的每个问题的url
full_url = question_url(one_title)
if full_url:
#下面的回调函数函数名可以是其他的,只有第一个回调函数名必须是parse。
yield Request(url=full_url,callback=self.question)
此时,我们需要找到 'item.py'文件,它的作用就跟Django中 'models.py' 相同。然后在里面输入以下代码。
class CsdnspiderItem(scrapy.Item):
title = scrapy.Field()
content = scrapy.Field()
接下来回到 'csdn_spider.py' 文件中,首先在最上方需要导入刚才创建的类。
from test1.items import CsdnspiderItem
再对每一个问题网址里面的内容进行筛选。
def question(self,response):
"""
提取每个问题中的回答内容
:param response:
:return:
"""
# print(response.body)
try:
one_question_title = response.xpath('//span[@class="title text_overflow"]/text()').extract()
one_question_title = one_question_title[0]
except:
one_question_title = 'none'
try:
one_question_contents = response.xpath('//div[@class="post_body post_body_min_h"]/text()').extract()
except:
one_question_contents = 'none'
contents_str = ''
for i in one_question_contents:
contents_str += i
contents_str = ' '.join(contents_str.split())
item = CsdnspiderItem()
item["title"] = one_question_title
item["content"] = contents_str
yield item
数据现在已经有了,那么我们把数据存到哪里呢?不要着急,scrapy已经为我们考虑到了。打开 'piplines.py' 文件,在这里,我们将进行我们的数据库存储操作。这里我们使用sqlite数据库。
import sqlite3
class CsdnspiderPipeline(object):
def __init__(self):
self.conn = sqlite3.connect('./../csdn.db')
self.cur = self.conn.cursor()
self.cur.execute(
"create table IF NOT EXISTS infos(id integer primary key autoincrement, question text,answer text);")
self.conn.commit()
def process_item(self, item, spider):
self.cur.execute('insert into infos(question,answer) values(?,?)',[item['title'],item['content']])
self.conn.commit()
return item
注意,我们还需要去'setting.py'文件中设置一下才可以使用。
ITEM_PIPELINES = {
'test1.pipelines.CsdnspiderPipeline': 300,
}
下面,我们在终端中输入 ‘scrapy crawl csdn_spider’就可以运行爬虫了。
有的时候,这样容易被封掉,我们可以使用浏览器模拟的操作,找到 ‘middlewares.py’ 文件,这时scrapy的中间件,我们在这里写浏览器模拟的类。
from scrapy.http import HtmlResponse
from selenium.common.exceptions import TimeoutException
import time
from selenium import webdriver
from selenium.webdriver.firefox.options import Options as FOptions
class SeleniumMiddleware(object):
def __init__(self):
self.options = FOptions()
self.options.add_argument('-headless') # 无头模式
self.browser = webdriver.Firefox(executable_path='E:\FireFox\geckodriver\geckodriver.exe',
firefox_options=self.options)
def process_request(self,request,spider):
try:
print("url is ::::::",request.url)
self.browser.get(request.url)
except TimeoutException as e:
print("超时")
time.sleep(2)
return HtmlResponse(url=self.browser.current_url,body=self.browser.page_source,
encoding="utf-8",request=request)
然后再 'setting.py' 中设置
DOWNLOADER_MIDDLEWARES = {
'test1.middlewares.SeleniumMiddleware': 543,
}
浏览器模拟需要用到的东西,在我的浏览器模拟的那个博客中有讲到,这里就不过多讲了。
现在算是一个比较完整的爬虫项目了。总的来说,比较简单,适合初学者入门学习。