本系统的这部分内容好像没什么好写的,就不从Scrapy基础开始说了,挑一些重点部分和容易出错的地方
来写一下。其中前程无忧和智联招聘用的是scrapy,拉勾网因为反爬太强了,用的是selenium,只能降低采集效率,用的是用selenium模拟登录,并且还得手动输入验证码(九宫格的验证码难以识别,找了好几个平台联系客服都说无法识别这种,就没怎么继续找了,虽然手动比较low)
1,对与用Scrapy爬取前程无忧和智联招聘的具体的过程就省略了。我爬的是这两个招聘网站中的IT岗位信息,前期没有设计好,导致爬虫数量很多,想要很好的入库就得用异步插入的方式,因为scrapy是Twisted异步框架,如果使用传统的pymysql,commit插入方式就很有可能导致入库不完整的情况,因为scrapy的采集速度要远远大于同步插入的速度,所以,也应该使用异步插入的方式来保存数据,具体方法如下:
导入twisted:
import MySQLdb from twisted.enterprise import adbapi import MySQLdb.cursors
定义MysqlTwistedPipline类:
class MysqlTwistedPipline(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):
# 使用twisted将mysql插入变成异步执行
if spider.name == 'qc_java' or spider.name == 'zl_java':
query = self.dbpool.runInteraction(self.do_insert_java, item)
query.addErrback(self.handle_error, item, spider) # 处理异常
elif spider.name == 'qc_python' or spider.name == 'zl_python':
query = self.dbpool.runInteraction(self.do_insert_python, item)
query.addErrback(self.handle_error, item, spider)
elif spider.name == 'qc_golang' or spider.name == 'zl_golang':
query = self.dbpool.runInteraction(self.do_insert_golang, item)
query.addErrback(self.handle_error, item, spider)
elif spider.name == 'qc_cplus' or spider.name == 'zl_cplus':
query = self.dbpool.runInteraction(self.do_insert_cplus, item)
query.addErrback(self.handle_error, item, spider)
elif spider.name == 'qc_bigdata' or spider.name == 'zl_bigdata':
query = self.dbpool.runInteraction(self.do_insert_bigdata, item)
query.addErrback(self.handle_error, item, spider)
elif spider.name == 'qc_arithmetic' or spider.name == 'zl_arithmetic':
query = self.dbpool.runInteraction(self.do_insert_arithmetic, item)
query.addErrback(self.handle_error, item, spider)
elif spider.name == 'qc_ai' or spider.name == 'zl_ai':
query = self.dbpool.runInteraction(self.do_insert_ai, item)
def handle_error(self, failure, item, spider):
print(failure)
具体mysql插入语句:
def do_insert_java(self, cursor, item):
insert_sql = "insert into `zp_java` (where_from,url,url_obj_id,job_name,company_name,salary_min,salary_max,job_city,experience_year,education_need,publish_date,job_advantage_tags,position_info,job_classification,crawl_time) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
item['url_obj_id'] = item['url_obj_id'] + "{0}".format(random.randint(61, 70))
cursor.execute(insert_sql,
(item["where_from"], item["url"], item["url_obj_id"], item["job_name"], item["company_name"], item["salary_min"], item["salary_max"],
item["job_city"], item["experience_year"], item["education_need"], item["publish_date"],
item["job_advantage_tags"], item["position_info"], item["job_classification"],
item["crawl_time"]))
2,使用Selenium模拟登陆拉钩代码:
try:
self.driver.get(self.login_url)
self.driver.find_element_by_css_selector("div:nth-child(2) > form > div:nth-child(1) > input").send_keys(
self.username)
time.sleep(3)
self.driver.find_element_by_css_selector("div:nth-child(2) > form > div:nth-child(2) > input").send_keys(
self.password)
time.sleep(4)
self.driver.find_element_by_css_selector(
"div:nth-child(2) > form > div.input_item.btn_group.clearfix > input").click()
time.sleep(2)
将拉勾网采集的数据一致遇到一个bug,就是字符串转义的问题,因为采集的字段有岗位详情描述,这是一个longtext,里面夹着一些特殊符号就会才入库的时候出现报错,要pymysql.escape_string()就可以很好的解决,这个函数是pymysql自带的。
效果截图: