上上篇博客记录了文章吧的文章爬取,作为一个学习爬虫的专业的程序猿,自然是离不开框架的
我们知道,我们爬取文章吧的文章,需要两步:
1,获取列表页的url,并构造该url的后续url爬取
2,在列表页获取详情页的url,进入详情页获取数据
问题来了,我们一般的scrapy项目,只能针对一个url发送request并获取response解析,我们怎么一边遍历列表页,一遍从详情页获取数据呢。
答案当然是,通用爬虫
我们已经知道了普通爬虫的创建方式,其实通用爬虫也相差不大
打开cmd终端,依旧是进入你需要的路径
执行以下命令
创建一个项目:
scrapy startproject wenzhangba
进入该项目
cd wenzhangba
创建一个通用爬虫
scrapy genspider -t crawl article www.wenzhangba.com
加黑的是爬虫名,斜体是域名
然后用pycharm打开
先写爬虫
article.py:
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from wenzhangba.items import WenzhangbaItem
class ArticleSpider(CrawlSpider):
name = 'article'
allowed_domains = ['www.wenzhangba.com']
start_urls = ['http://www.wenzhangba.com/ganrengushi/list_20_1.html']
rules = (
#设置文章列表页爬取规则,
#根据列表页链接设置爬取链接规则,
#列表页无需提取数据,因此不需要callback方法
#需要后面的列表页数据,允许跟进爬取
Rule(LinkExtractor(allow=r'.+/ganrengushi/list_20_\d+.html'), follow=True),
#设置文章详情页爬取规则
# 根据详情页链接设置爬取链接规则,
# 详情页需提取数据,因此需要callback方法
# 不需要在详情页跟进爬取
Rule(LinkExtractor(allow=r'.+/ganrengushi/\d+/\d+.html'), callback='parse_detail', follow=False),
)
def parse_detail(self, response):
title = response.xpath("//div[@class='c_a_info']//h1/a/text()").get().strip()
# print(title)
date = response.xpath("//div[@class='a_tit']//span[@class='s1']/text()").get().strip()
# print(date)
#作者这项有一定的问题
#1,该文章可能是个人写作投稿,class属性是s2
#2,转载或声明来源,class属性是s5
#3,前面是作者,后面是来源,且作者名字是可以跳转的链接,此时获取的作者只有“作者:”两个字,没有名字
authors = response.xpath("//div[@class='a_tit']//span[@class='s2']/text()|"
"//div[@class='a_tit']//span[@class='s5']/text()").getall()
if authors[0] == "作者:" :
author = authors[1]
else:
author =authors[0]
# print(author)
#这里获取文章内容,不做去除标签等处理。
#原因是爬下来的数据可以直接从数据库中拿出来放到网站
#避免使用时前端需要再次处理的麻烦,我同学说的。
content = response.xpath("//div[@class='a_detail']").get()
item = WenzhangbaItem(title=title, date=date, author=author, content=content)
yield item
一些介绍都放在代码的注释中了。不在多说
然后
items.py:
import scrapy
class WenzhangbaItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
title = scrapy.Field()
date = scrapy.Field()
author = scrapy.Field()
content = scrapy.Field()
piplines.py:
import pymysql
class WenzhangbaPipeline(object):
def __init__(self, host, database, user, password, port):
#构造数据库参数
self.host = host
self.database = database
self.user = user
self.password = password
self.port = port
@classmethod
def from_crawler(cls, crawler):
return cls(
host=crawler.settings.get("MYSQL_HOST"),
database=crawler.settings.get("MYSQL_DATABASE"),
user=crawler.settings.get("MYSQL_USER"),
password=crawler.settings.get("MYSQL_PASSWORD"),
port=crawler.settings.get("MYSQL_PORT"),
)
def open_spider(self, spider):
self.db = pymysql.connect(self.host,self.user,self.password,self.database,charset="utf8",port=self.port)
self.cursor = self.db.cursor()
def process_item(self, item, spider):
data = dict(item)
sql = """
insert into article(id, title, pub_time, author, content) values(null, %s, %s, %s, %s)
"""
self.cursor.execute(sql,(item['title'], item['date'], item['author'], item['content']))
self.db.commit()
return item
def close(self, spider):
self.db.close()
设置settings.py
关闭协议:
ROBOTSTXT_OBEY = False
设置请求头:
DEFAULT_REQUEST_HEADERS = { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'en', 'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 ' '(KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36', }
设置并编写piplines配置
ITEM_PIPELINES = { 'wenzhangba.pipelines.WenzhangbaPipeline': 300, } MYSQL_HOST = 'localhost' MYSQL_DATABASE = 'wenzhangba' MYSQL_PORT = 3306 MYSQL_USER = 'root' MYSQL_PASSWORD = '123'
最后,star.py:
from scrapy import cmdline
cmdline.execute("scrapy crawl article".split())
那么,代码就优化完成了,它会按照你给的规则抓取数据
看看数据库:
这里是一部分,因为是优化代码,数据用不到,所以只抓取了关键几项,没有上次获取的数据多。
努力学习。
以上