2018-4-8
scrapy 工作流程:engine获得spiders内url,请求调度程序,对url进行爬取,Downloader返回response给爬虫引擎,引擎返回response给spiders,然后spiders处理item,发送给管道处理,然后把结果返回给调度器,然后重复此过程
一、 首先是Scrapy普通爬虫,没有什么可讲
三、然后爬虫数据需要存入数据库,个人熟悉MySQL等关系型数据库,所以以mysql为主
a. 爬虫第一步当然是需要把ROBOTSTXT_OBEY改成False,
b.如果过程总遇到导包问题,应该不出意外需要加这句话
d.然后在items.py内将类对象属性进行处理,建议做的时候线debug一下,以防得到的属性值为数组没转换,对属性处理如下:
a.如果不设置,那么Scrapy将会自动设置为Scrapy
五、接下来就是验证码问题了,tesseract-ocr准确性不高,个人觉得用在线打码方式最方便,当然人工打码准确率是最高的
a.Selenium集成到Scrapy中,这里就需要信号链了。
b.同样是操作中间件,在Spider里面,即自己写的爬虫文件里面先init一个browser,然后connect一个信号链来检测爬虫完后关闭浏览器
七、最后是ElasticSearch了,非关系型数据库,花点时间研究入门也不是很难,用法也是pip install,导包,connect,然后在item里面save一下,当然想要集成到python内使用,需要install的是elasticsearch_dsl,还有elasticsearch_rtf,适合做日志分析系统,爬虫引擎
八、利用scrapyd将爬虫部署,windows上需要在个scrapyd-deploy下新建一个同名的.bat文件,内容是:
a.去github clone scrapy-redis放在项目工程中,Spider继承RedisSpider就可以了,简单使用,github都有讲,主要是利调度处理url
十、如有问题,请指出,谢谢
scrapy 工作流程:engine获得spiders内url,请求调度程序,对url进行爬取,Downloader返回response给爬虫引擎,引擎返回response给spiders,然后spiders处理item,发送给管道处理,然后把结果返回给调度器,然后重复此过程
一、 首先是Scrapy普通爬虫,没有什么可讲
scrapy startproject name1 //新建Scrapy爬虫项目
scrapy genspider name2 //新建spider
二、 其次是整站爬虫
scrapy genspider -t crawl lagou www.lagou.com //新建爬虫,自动生成的Spider继承CrawSpider
在Spider下面会自动生成一个Rule,如:
rules = (
Rule(LinkExtractor(allow=r'https://www.lagou.com/jobs/\d+.html'), callback='parse_job', follow=True),
)
第一个是正则匹配,只要匹配的链接都会去爬取,然后回调parse_job这个函数,follow=True表示继续跟踪,参数含义看一下源码都能懂,其中还有deny(不匹配什么url)参数等
三、然后爬虫数据需要存入数据库,个人熟悉MySQL等关系型数据库,所以以mysql为主
a. 爬虫第一步当然是需要把ROBOTSTXT_OBEY改成False,
b.如果过程总遇到导包问题,应该不出意外需要加这句话
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(BASE_DIR, 'ArticleSpider'))
c.数据放到数据库需要settings.py里面的ITEM_PIPELINES={....}首先取消注释
d.然后在items.py内将类对象属性进行处理,建议做的时候线debug一下,以防得到的属性值为数组没转换,对属性处理如下:
job_details = scrapy.Field(
input_processor=MapCompose(return_value)
)
其中,return_value是一个自定义的函数,MapCompose()括号内可以填写多个函数进行处理
当然,如果得到的属性是数组华,可以自动一一个ItemLoader,设置default_output_processor=TakeFirst()即可
e.然后可以在类里面定义一个插入数据到数据库的函数,例如
def get_insert_sql(self):
insert_sql = """
insert into lagou(url, job_id, title, salary, job_city, work_years, degree_need, job_type,publish_time,job_desc,crawl_time)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
ON DUPLICATE KEY UPDATE salary=VALUES(salary), work_years=VALUES(work_years),job_desc=VALUES(job_desc)
"""
params = (self["url"], self["job_id"], self["title"], self["salary"], self["job_city"], self["work_years"]
, self["degree_need"], self["job_type"], self["publish_time"],
self["job_desc"],
self["crawl_time"].strftime(SQL_DATETIME_FORMAT))
return insert_sql, params
g.然后在Pipeline的process_item内,直接调用
insert_sql, params = item.get_insert_sql()
self.cursor.execute(insert_sql, params)
self.conn.commit(
h.上面这种是同步操作,肯定不是我们想要的,然后twisted就出场了
import MySQLdb
from twisted.enterprise import adbapi
import MySQLdb.cursors
重写from_settings(cls,settings)
具体代码如下:
class MySqlTwistedPipelines(object):
def __init__(self, dbpool):
self.dbpool = dbpool
@classmethod
def from_settings(cls, settings):
dbparms = dict(
host=settings['MYSQL_HOST'],
db=settings['MYSQL_DBNAME'],
user=settings['MYSQL_USER'],
passwd=settings['MYSQL_PASSWORD'],
charset='utf8',
cursorclass=MySQLdb.cursors.DictCursor,
use_unicode=True,
)
dbpool = adbapi.ConnectionPool('MySQLdb', **dbparms)
return cls(dbpool)
def process_item(self, item, spider):
query = self.dbpool.runInteraction(self.do_insert, item)
query.addErrback(self.handler_error) # 处理异常
def handler_error(self, failure):
# 处理异步插入的异常
print(failure)
def do_insert(self, cursor, item):
insert_sql, params = item.get_insert_sql()
cursor.execute(insert_sql, params)
i. 然后只剩下同步的时候,数据库连接了
def __init__(self):
self.conn = MySQLdb.connect('127.0.0.1', 'username', 'password', '***_spider', charset='utf8', use_unicode=True)
self.cursor = self.conn.cursor()
四、数据也放到数据库了,那么需要考虑的问题就是设置User_Agent和ip
a.如果不设置,那么Scrapy将会自动设置为Scrapy
b.User_Agent也不能总是一个,如果数据多,实时更换是有必要的,可以选择在setting里面放一个user_agent list,每次随机取,但是这种情况下,每次请求都要执行随机取user_agent的函数。既然Scrapy有Middlewares,就可以利用一个比较好用的user_agent库(fake_useragent,每次随机生成user_agnet),每次在中间件里面process_request(self,request, spider)函数内对headers进行设置user_agent
c.当然上一步需要把中间件开启,在setting里面取消注释即可,并切需要将scrapy自带的中间件设置为None 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None
d.接下来就是动态ip,在西刺网上都是高匿名的ip,不过每次爬取下来然后使用时,发现好多都并不能用,都要先进行访问一下,不能用再筛选,数据不多还可以,数据一旦多起来就慢了。这里使用scrapy_proxies,也是在github上有,同User_Agent设置一样
五、接下来就是验证码问题了,tesseract-ocr准确性不高,个人觉得用在线打码方式最方便,当然人工打码准确率是最高的
a.Selenium集成到Scrapy中,这里就需要信号链了。
b.同样是操作中间件,在Spider里面,即自己写的爬虫文件里面先init一个browser,然后connect一个信号链来检测爬虫完后关闭浏览器
from scrapy.xlib.pydispatch import dispatcher
from scrapy import signals
def __init__(self):
self.browser = webdriver.Firefox() # executable_path=""
super().__init__()
dispatcher.connect(self.spider_closed, signals.spider_closed)
c.在中间件里面直接spider.browser获取browser即可
def process_request(self, request, spider):
if spider.name == "lagou":
spider.browser.get(request.url)
import time
time.sleep(1)
return HtmlResponse(url=spider.browser.current_url, body=spider.browser.page_source,
encoding="utf-8", request=request)
六、接下来就是phantomjs无界面浏览器继承到scrapy了,和上面类似
七、最后是ElasticSearch了,非关系型数据库,花点时间研究入门也不是很难,用法也是pip install,导包,connect,然后在item里面save一下,当然想要集成到python内使用,需要install的是elasticsearch_dsl,还有elasticsearch_rtf,适合做日志分析系统,爬虫引擎
八、利用scrapyd将爬虫部署,windows上需要在个scrapyd-deploy下新建一个同名的.bat文件,内容是:
@echo off
"D:\programfiles\python3.6\python.exe" "D:\programfiles\python3.6\Scripts\scrapyd-deploy" %*
九、最后就是爬虫的分布式了,当然用redis
a.去github clone scrapy-redis放在项目工程中,Spider继承RedisSpider就可以了,简单使用,github都有讲,主要是利调度处理url
十、如有问题,请指出,谢谢