前期准备:
这次爬虫用的都是python自带的包,所以只用准备一个pymongo用于mongodb数据库连接就可以了
pip install pymongo
第一步:目标站点分析
url = ‘http://sou.zhaopin.com/jobs/searchresult.ashx?p=0&jl=%E5%85%A8%E5%9B%BD&kw=%E5%A4%A7%E6%95%B0%E6%8D%AE&isadv=0’
观察上面url 可以发现 智联招聘用4个参数定义了搜索的范围 其中 P 为 page 也就是页码。jl 为地域范围 这里是全国,KW 为搜索内容 这里我搜索的是关于大数据方面的,isadv这个我没去研究。不过对搜索没有影响。
所以,我们可以通过这个定制搜索的内容来得到索引页的url :
def get_page_index(jl,keyword,page=1):
data = {
'jl':jl,
'kw':keyword,
'p':page,
'isadv': 0
}
url = 'http://sou.zhaopin.com/jobs/searchresult.ashx?'+ urlencode(data)
print('[+] 到达索引页: %s' % url)
return download_html(url)
再设置一个confi脚本,将其引入爬取智联招聘.py文件中。
from config import *
第二步:解析索引页中所有职位的url
智联招聘的每个职位url:
示例:http://jobs.zhaopin.com/208149611251243.htm
http://jobs.zhaopin.com/407340480250023.htm
http://jobs.zhaopin.com/390314230250020.htm
观察上面职位url,可以发现 都是由http://jobs.zhaopin.com/+15位数字+.htm 组成
通过这个,我们可以用re模块将页面所有的url连接解析出来,然后再匹配满足上面示例形式的url。
具体代码如下:
def get_index_href(html):
pattern = re.compile('<a[^>]+href=["\'](.*?)["\']', re.IGNORECASE)
links = pattern.findall(html)
href = 'http://jobs.zhaopin.com/\d{15}.htm'
for link in links: # 取到所有的a标签中的链接,
if re.match(href, link) : # 进行匹配
yield link
return None
第三步:进入职位的url抓取职位信息
我们需要的是上面的这些信息。
查看网页源代码,智联招聘对爬虫来说很友好,每个我们需要的内容都包含在<strong>标签下,我们很容易通过正则表达式把所有的需要的信息抓取下来。这里推荐大家一个在线的正则表达式网站:在线正则表达式测试
我用来匹配的表达式:
pattern = '<li><span>[\u4e00-\u9fa5 :]+</span>.*?>([\u4e00-\u9fa5 :\w\s/-]+).*>'
tittle_pattern = '<h1>([\u4e00-\u9fa5 :+、()\.\w\s/-]+.*?)</h1>'
第四步: 循环
循环其实在爬虫中是很好理解和琢磨的,所以这里就不再介绍了。最后我们把爬下来的数据写入mongodb和csv文件中,用在后续的机器学习数据分析。
csv文件的写入示例:
import csv
with open("name.csv", "w") as csvfile:
# 写标题
fileheader = ["name", "score"]
dict_writer = csv.DictWriter(csvFile, fileheader)
# 写数据名,可以自己写如下代码完成:
dict_writer.writerow(dict(zip(fileheader, fileheader)))
# 之后,按照(属性:数据)的形式,将字典写入CSV文档即可
dict_writer.writerow({"name": "Li", "score": "80"})
第五步:引入多线程与多进程
写模块的时候,一般多进程和多线程用在 if __name__ == '__main__'之后,前后对比一下,因为python的线程锁GIL,其实多线程并不会有很好的效果,不过对于多核的处理器多进程确实会提高很多效率。在python中多线程和多进程使用方法很简单。
#多线程
pool = multiprocessing.Pool()
# 多进程
thread = threading.Thread(target=pool.map,args = (main,[x for x in range(1, 100)]))
thread.start()
thread.join()
实例代码:
import csv,re,threading,multiprocessing
from urllib.parse import urlencode
from urllib.request import urlopen,Request,urlparse,build_opener,install_opener
from urllib.error import URLError,HTTPError
import pymongo as pymongo
from config import *
def download_html(url):
headers = {'User-Agent': "User-Agent:Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)"}
request = Request(url, headers=headers)
try:
html = urlopen(request).read().decode()
except HTTPError as e:
html = None
print('[W] 下载出现服务器错误: %s' % e.reason)
return None
except URLError as e:
html = None
print("[E] 站点不可达: %s" % e.reason)
return None
return html
def get_page_index(jl,keyword,page=1):
data = {
'jl':jl,
'kw':keyword,
'p':page,
'isadv': 0
}
url = 'http://sou.zhaopin.com/jobs/searchresult.ashx?'+ urlencode(data)
print('[+] 到达索引页: %s' % url)
return download_html(url)
def get_index_href(html):
pattern = re.compile('<a[^>]+href=["\'](.*?)["\']', re.IGNORECASE)
links = pattern.findall(html)
href = 'http://jobs.zhaopin.com/\d{15}.htm'
for link in links: # 取到所有的a标签中的链接,
if re.match(href, link) : # 进行匹配
yield link
return None
def page_parser(html,fileheader):
pattern = '<li><span>[\u4e00-\u9fa5 :]+</span>.*?>([\u4e00-\u9fa5 :\w\s/-]+).*>'
data = re.findall(pattern,html)
try:
tittle_pattern = '<h1>([\u4e00-\u9fa5 :+、()\.\w\s/-]+.*?)</h1>'
tittle_find = re.search(tittle_pattern, html)
tittle = tittle_find.group(1)
data.insert(0, tittle)
except:
print('职业名称未找到')
data.insert(0,'大数据职位')
clear_data = dict(zip(fileheader,data))
return clear_data
def writer_to_mongodb(res):
if db[MONGOTABE].insert(res):
print('herf= {} save success'.format(url))
return True
print('save fail')
return False
def write_csv_header(fileheader):
with open("智联招聘.csv", "w",newline='') as csvfile:
writer = csv.DictWriter(csvfile, fileheader)
writer.writeheader()
def main(page):
fileheader = ['职位名称','职位月薪', '工作地点', '发布日期', '工作性质', '工作经验', '最低学历', '招聘人数', '职位类别', '公司规模', '公司性质', '公司行业']
html = get_page_index(jl,keyword,page)
for link in get_index_href(html):
print('[+] 找到目标站点: %s' % link)
parser_html = download_html(link)
dict = page_parser(parser_html,fileheader)
#写入数据库 mongodb
#writer_to_mongodb(dict)
with open("智联招聘.csv", "a",newline='') as csvfile:
print(' 正在写入csv文件中.....')
writer = csv.DictWriter(csvfile, fieldnames=fileheader)
writer.writerow(dict)
if __name__ == '__main__':
client = pymongo.MongoClient(MONGO_URL)
db = client[MONGODB]
fileheader = ['职位名称','职位月薪', '工作地点', '发布日期', '工作性质', '工作经验', '最低学历', '招聘人数', '职位类别', '公司规模', '公司性质', '公司行业']
write_csv_header(fileheader)
#多线程
pool = multiprocessing.Pool()
# 多进程
thread = threading.Thread(target=pool.map,args = (main,[x for x in range(1, 100)]))
thread.start()
thread.join()
效果展示: