概念图
快速入门
在pycharm 安装scrapy
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple scrapy
安装后创建项目
scrapy startscrapy game
创建后目录结构如图
项目创建后,创建spider爬虫
scrapy genspider xiao 4399.com
xiao是爬虫的名字,4399.com是爬取的范围,执行完毕后会创建一个xiao.py的spider
返回对象在parse解析,例如print(resopnse.txt)等,注意需要设置日志级别,否则会打印出很多不需要的信息
settings还可以配置,user-agent,协程的并发数量,robot协议等
然后传递数据到管道,在管道进行各种操作,持久化到数据库等
传递数据到管道用关键词yield
管道默认不开启,需要手动在settings.py中解除注释
管道可以有多个并存,且数值越小,优先级越高
运行scrapy代码,需要在terminal输入,xiao是spider名称
scrapy crawl xiao # xiao是spider名称
创建项目步骤总结
在python控制台想对scrapy crawl python的结果进行搜索,很麻烦,在run中搜索很方便,可以使用一下方式,将terminal的结果转到run显示
spider取数据,
class ShuangseqiuSpider(scrapy.Spider):
name = "shuangseqiu"
allowed_domains = ["500.com"]
start_urls = ["https://datachart.500.com/ssq/history/outball.shtml"]
def parse(self, response, *args, **kwargs):
response.css('.class_t_tr1')
for tr in response.css('.t_tr1'):
qihao=tr.css('td::text').extract_first()
date=tr.xpath('.//td[2]/text()').extract_first()
red_balls=tr.xpath('.//td[@class="t_tdb1 t_cfont1"]/text()').extract()
blue_ball= tr.xpath('.//td[@class="t_cfont4"]/text()').extract_first()
cai=CaipiaoItem()
cai['qihao']=qihao
cai['date']=date
cai['red_ball']=red_balls
cai['blue_ball']=blue_ball
yield cai
将结果封装成item,进行传递
class CaipiaoItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
qihao=scrapy.Field()
red_ball=scrapy.Field()
blue_ball=scrapy.Field()
date=scrapy.Field()
到pipeline数据持久化
记得要return数据,不然后面其他管道接收不到,
多个pipeline之间通过在settings设置优先级,数值越小,优先级越高
csv
class CaipiaoPipeline:
def open_spider(self, spider):
self.f=open('./test.csv', 'a', encoding='utf-8')
def close_spider(self, spider):
if self.f:
self.f.close()
def process_item(self, cai, spider):
print("csv---------")
self.f.write(f'{cai["qihao"]},{cai["date"]},{"_".join(cai["red_ball"])},{cai["blue_ball"]}\n')
return cai
mysql
导包
import pymsql
创建库
create database spider;
创建表
create table capiao(
id int(11) primary key auto_increment,
qihao varchar(100),
date date,
red_ball varchar(100),
blue_ball varchar(100)
);
pipeline
class CaipiaoMySqlPipeline:
def open_spider(self, spider):
self.conn=pymysql.Connection(
host=MYSQL['host'],
port=MYSQL['port'],
user=MYSQL['user'],
passwd=MYSQL['passwd'],
database=MYSQL['database'],
)
def close_spider(self, spider):
if self.conn:
self.conn.close()
def process_item(self, cai, spider):
try:
#创建游标
cursor=self.conn.cursor()
sql="insert into capiao (qihao,date,red_ball,blue_ball) values (%s,%s,%s,%s)"
cursor.execute(sql,(cai["qihao"],cai["date"],"_".join(cai["red_ball"]),cai["blue_ball"]))
self.conn.commit()
except:
self.conn.rollback()
finally:
if cursor:
cursor.close()
print("msyql-------------")
return cai
项目实战,扒一个风景图片网站
创建爬虫项目
scrapy startproject fengjingtu
创建spider
scrapy genspider fengjingt tupianzj.com
到settings调整log级别
LOG_LEVEL = 'WARNING'
写爬虫业务逻辑
spider:
class FengjingtSpider(scrapy.Spider):
name = "fengjingt"
allowed_domains = ["desk.zol.com.cn","baidu.com","inews.gtimg.com"]
start_urls = ["https://desk.zol.com.cn/fengjing/"]
def parse(self, response,**kwargs):
#获取图片url
lis=response.xpath("//li[@class='photo-list-padding']")
for li in lis:
href=li.xpath("./a/@href").extract_first()
if href.endswith(".exe"):
continue
#print(href) #/bizhi/10055_120350_2.html
#拼接url,使用urljoin,自动对/进行分析,并拼接
href=response.urljoin(href)
yield Request(href,callback=self.new_parse)
break
def new_parse(self, response, **kwargs):
src=response.xpath('//*[@id="bigImg"]/@src').extract_first()
yield {
'src':src,
}
pipeline
from scrapy.pipelines.images import ImagesPipeline
from scrapy import Request
class FengjingtuPipeline:
def process_item(self, item, spider):
return item
# scrapy提供的图片下载功能
class TupianPipeline(ImagesPipeline):
#以下3个方法名称固定,都需要重写父类
# 请求图片的url
def get_media_requests(self, item, info):
headers={
'referer': 'https://desk.zol.com.cn/bizhi/',
"USER_AGENT": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36"
}
src=item["src"]
src='https://inews.gtimg.com/om_bt/O6SG7dHjdG0kWNyWz6WPo2_3v6A6eAC9ThTazwlKPO1qMAA/641'
resp=Request(src,meta={'src':src})
print(resp)
print(1)
yield resp
# 保存图片的路径,scrapy帮我们处理
def file_path(self, request, response=None, info=None, *, item=None):
src=request.meta['src']
file_name=src.split('/')[-1]
return f'./{file_name}.jpg'
# 收尾工作
def item_completed(self, results, item, info):
pass
设置cookie模拟登录
第一种方式,在settings中添加cookie
如果需要cookie 在settings里设置的不生效,因为scrapy默认中间件有cookie,需要设置一个属性把默认的关闭
测试过程发现 17k小说对 referer要求较高,有时候访问不成功,更换referer后就成功。
并且scrapy有缓存,测试成功后,立马把referer变化,继续运行,依然还可以爬到
第二种方式,在spider中,重写start_request方法,把cookie传过去,cookie需要是字典
第三种方式,直接post方式调用login接口,body需要是字符串,不能是字典,可以用一个库来转换。
自动拼接body过程:
from urllib.parse import urlencode
s=urlencode(data)
手动拼接body过程:
post登录后,回调login_success,然后继续请求,并用scrapy默认方法解析
中间件
中间件是引擎到下载器或引擎到爬虫之间的组件,前者叫下载器中间件,后者叫爬虫中间件,
爬虫中间件用的非常少,不做介绍,主要是下载器中间件。
逻辑图
需要去settings解除中间件注释:
可以有多个中间件,数字越小的,离引擎 越近,优先级越高
模拟每次请求都更换ua
先在settings中放入ua合集
然后去下载器中间件的请求环境设置ua
from settings import headers_list
from random import choice
class MidDownloaderMiddleware:
def process_request(self, request, spider):
UserAgent = choice(headers_list)['user-agent']
request.headers['User-Agent'] = UserAgent
print(UserAgent)
return None
结果如下
设置代理ip
在settings添加代理中间件
在middlewares写proxy
class ProxyDownloaderMiddleware:
def process_request(self, request, spider):
proxy='183.215.23.242:9091'
request.meta['proxy'] = f"http://{proxy}"
return None
分布式爬虫
只需要在spider中改变2处
在settings中做好redis及相关配置
爬虫服务器部署
首先创建虚拟机,并在虚拟机安装scrapyd
然后在客户端安装scrapyd,并修改scrapy.cfg,在终端执行
scrapyd-deploy 部署的地方名 -p 项目名
curl调用接口,执行爬虫
关闭爬虫
容易出现的问题:
访问延时没有开
pipline没有开启
spider,没有写资源的域名,
爬图片的时候,没有配置IMAGE_STORE
如果出现302 记得加上MEDIA_ALLOW_REDIRECTS=True