Repository navigation
Expand file tree
/
Copy pathfeed.xml
More file actions
639 lines (359 loc) · 70.5 KB
/
Copy pathfeed.xml
File metadata and controls
639 lines (359 loc) · 70.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom">
<title>Naelah Nordin</title>
<subtitle>Super-fast Jekyll framework</subtitle>
<updated>2021-04-16T13:12:02+08:00</updated>
<id>http://0.0.0.0:4321/</id>
<generator uri="https://sparanoid.com/lab/amsf/" version="2.0.18">Almace Scaffolding</generator>
<link rel="alternate" type="text/html" hreflang="en" href="http://0.0.0.0:4321/" />
<link rel="self" type="application/atom+xml" href="http://0.0.0.0:4321/feed.xml" />
<author>
<name>Naelah Nordin</name>
<uri>http://0.0.0.0:4321/</uri>
<email>naelahnordin@gmail.com</email>
</author>
<entry>
<title>Jobstreet Scraper</title>
<id>http://0.0.0.0:4321/Scraping-Jobstreet-Posts.html</id>
<link rel="alternate" type="text/html" href="http://0.0.0.0:4321/Scraping-Jobstreet-Posts.html" />
<published>2021-04-12T00:00:00+08:00</published>
<updated>2021-04-16T13:01:10+08:00</updated>
<author>
<name>Naelah Nordin</name>
<uri>https://naelahnordin.com/</uri>
<email>naelahnordin@gmail.com</email>
</author>
<content type="html" xml:base="http://0.0.0.0:4321/">
<p>Each website is built by different individuals so there is no one magic script that can scrape different websites because the art of scraping lies in deconstructing the html elements into separate objects that we can extract or “scrape” the information from. Of course there are scraping tools out there that automate these scripts based on your preference (literally google free web scraping tools, there are a bunch of them). I have tried several of these tools and I always end up getting frustrated and going back to writing the codes myself because a) they always have a pricing tier despite claiming to be free, and b) the process is overcomplicated and some websites are just not built intuitively that these tools can easily automate. This tutorial specifies the necessary steps to scrape data from Jobstreet Malaysia but the process of crawling and scraping boils down to a few basic steps that can be applied to almost any website.</p>
<h1 id="web-scraping-vs-web-crawling">Web Scraping vs. Web Crawling</h1>
<p>These two terms get thrown out a lot when it comes to automating data acquisition from the internet. Sometimes it is used interchangably to mean the same thing but they are actually different methods that are used together in achieving the same goal which is to extract information from a website that is presented in a way that has a pattern. This pattern is the key in writing codes that can iterate from one page to another. For example let’s look at jobstreet’s search page.</p>
<p class="browser"><img src="assets/img/jobstreet-screenshot-1.png" alt="Image" /></p>
<p>There are several patterns here that we can leverage on. At this point you have to ask yourself, how do I get all these links? If you weren’t aiming to crawl and to scrape, how would you manually do it? In this example, jobstreet provides a paginated result page. There are a fixed amount of number of links in each page and they are all in similar looking boxes which suggests that the styling would use the same ID, this is important for scraping later, but as for now, in order to crawl and get all the relevant links, you need to determine how the data is populated.</p>
<p>Another example is Facebook which does not have pagination, on the contrary it uses infinite scrolling so the method of crawling is completely different. Even if a website has pagination, we need to determine how the website processes user input and goes to the next page. Most commonly, websites implement URL parameters which means the number of page is in the url like <code class="language-plaintext highlighter-rouge">www.website.com?page=2</code> or <code class="language-plaintext highlighter-rouge">www.website.com/2/</code>. In these cases, going from one page to another is pretty straightforward. However, some websites implementing things like servlets and do not take parameters in the URL are trickier to crawl but still possible. You can maybe imitate certain buttons clicking or imitate scrolling, anything is possible.</p>
<ol>
<li>
<p>Search keyword is appended in the url</p>
<p>Because jobstreet uses URL parameters, it’s just a matter of modifying the URL in each iteration. Here we can also see that the keyword is appended at the end of the URL as such, <code class="language-plaintext highlighter-rouge">www.jobstreet.com.my/en/job-search/data-jobs</code>, this allows for querying multiple keywords.</p>
</li>
<li>
<p>There are 1832 job postings, with 30 jobs listed on each page</p>
<p>This means we only need math to determine how many iterations we need to go through all pages. We determine the class name of the text <code class="language-plaintext highlighter-rouge">1832 jobs</code> by inspecting the element and from there we can simply do the following</p>
</li>
</ol>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="kn">import</span> <span class="nn">math</span>
<span class="k">def</span> <span class="nf">get_page_number</span><span class="p">(</span><span class="n">result</span><span class="p">):</span>
<span class="c1"># assuming total_jobs is processed and converted to integer
</span> <span class="c1"># total_jobs divide by 30 pages and take the ceiling
</span> <span class="n">page_number</span> <span class="o">=</span> <span class="n">math</span><span class="p">.</span><span class="n">ceil</span><span class="p">(</span><span class="n">result</span><span class="o">/</span><span class="mi">30</span><span class="p">)</span>
<span class="k">return</span> <span class="n">page_number</span></code></pre></figure>
<p>So now we have the page number, 8 which allows us to crawl all 8 page results and scrape the relevant links.</p>
<h1 id="is-it-legal">Is it Legal?</h1>
<p>The short answer is an astounding <strong>Yes!</strong> We are not hacking into anyone’s private account. We are simply automating the process of one person manually clicking through a website 200 times and copying and pasting information, into a program that we can leave for hours and maybe days that would ultimately save our time but has no damaging consequences to the website owners. Ethically though, what we do with the information is another issue and the fact that scraping as a tool for morally ambiguous activity is up for debate, like how <a href="https://www.metro.us/everything-to-know-about-facemash-the-site-zuckerberg-created-in-college-to-rank-hot-women/">Mark Zuckerberg scraped images of women in sorority houses in Harvard</a> to create a website comparing which woman is hotter is unanimously frowned upon but it is 100% legal.</p>
<h1 id="getting-started">Getting Started</h1>
<p>To run the script, simply</p>
<ol>
<li>Clone <a href="https://github.com/naelah/jobstreet-scraper">this Github repository</a></li>
<li>Create a virtual python environment (optional). Run the following script in terminal
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>python -m venv venv
source venv/bin/activate
</code></pre></div> </div>
</li>
<li>Once the environment is activated, install the requirements
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip install -r requirements.txt
</code></pre></div> </div>
</li>
<li>Download <a href="https://chromedriver.chromium.org/">chromedriver</a> based on your chrome version and <a href="https://stackoverflow.com/questions/4423061/view-http-headers-in-google-chrome">determine your version and header here</a></li>
<li>Modify <code class="language-plaintext highlighter-rouge">jobstreet_scraper.py</code> accordingly</li>
</ol>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c1"># Modify headers to match your device
</span><span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="s">'User-Agent'</span><span class="p">:</span><span class="s">'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36'</span><span class="p">}</span>
<span class="c1"># Insert path to your chromedriver here
</span><span class="n">path</span> <span class="o">=</span> <span class="s">"/usr/local/Caskroom/chromedriver/88.0.4324.96/chromedriver"</span>
<span class="p">...</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="c1"># determine the keywords that you want to query, it can be one or more but must be in a list
</span> <span class="n">key_words</span> <span class="o">=</span> <span class="p">[</span><span class="s">'agriculture'</span><span class="p">,</span><span class="s">'crop'</span><span class="p">]</span>
</code></pre></figure>
<p>Run <code class="language-plaintext highlighter-rouge">python jobstreet_scraper.py</code> in terminal and you should see the scraping process starting.</p>
<h1 id="breakdown-of-functions">Breakdown of functions</h1>
<p>The script consists a few key steps in successfully crawling and scraping which are</p>
<p><strong>1. Configure driver to browse web pages &amp; BeautifulSoup4 to scrape html codes</strong></p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c1"># configuration
</span><span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="s">'User-Agent'</span><span class="p">:</span><span class="s">'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36'</span><span class="p">}</span>
<span class="n">path</span> <span class="o">=</span> <span class="s">"/usr/local/Caskroom/chromedriver/88.0.4324.96/chromedriver"</span>
<span class="n">driver</span> <span class="o">=</span> <span class="n">Chrome</span><span class="p">(</span><span class="n">executable_path</span><span class="o">=</span><span class="n">path</span><span class="p">)</span>
<span class="c1"># url template accepting keyword and page number
</span><span class="n">base_url</span> <span class="o">=</span> <span class="s">"https://www.jobstreet.com.my/en/job-search/{}-jobs/{}/"</span>
<span class="c1"># url generation https://www.jobstreet.com.my/en/job-search/agriculture-jobs/1/
</span><span class="n">url</span> <span class="o">=</span> <span class="n">base_url</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="c1"># visits the specified url
</span><span class="n">driver</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="c1"># parses html page into selectable elements
</span><span class="n">soup</span> <span class="o">=</span> <span class="n">BeautifulSoup</span><span class="p">(</span><span class="n">driver</span><span class="p">.</span><span class="n">page_source</span><span class="p">,</span> <span class="s">'html.parser'</span><span class="p">)</span></code></pre></figure>
<p><strong>2. Iterate through keywords</strong></p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">key_words</span> <span class="o">=</span> <span class="p">[</span><span class="s">'agriculture'</span><span class="p">,</span><span class="s">'crop'</span><span class="p">]</span>
<span class="n">dfs</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">key_words</span><span class="p">:</span>
<span class="n">key_df</span> <span class="o">=</span> <span class="n">page_crawler</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
<span class="n">dfs</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">key_df</span><span class="p">)</span>
</code></pre></figure>
<p><strong>2. Get Page number</strong></p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">def</span> <span class="nf">get_page_number</span><span class="p">(</span><span class="n">keyword</span><span class="p">):</span>
<span class="c1">#input: keyword for job_postings
</span> <span class="c1">#output: number of pages
</span>
<span class="n">url</span> <span class="o">=</span> <span class="n">base_url</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">driver</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="n">soup</span> <span class="o">=</span> <span class="n">BeautifulSoup</span><span class="p">(</span><span class="n">driver</span><span class="p">.</span><span class="n">page_source</span><span class="p">,</span> <span class="s">'html.parser'</span><span class="p">)</span>
<span class="n">result_text</span> <span class="o">=</span> <span class="n">soup</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="s">"span"</span><span class="p">,{</span><span class="s">"class"</span><span class="p">:</span> <span class="s">"FYwKg _2Bz3E C6ZIU_0 _1_nER_0 _2DNlq_0 _29m7__0 _1PM5y_0"</span><span class="p">})</span>
<span class="n">results</span> <span class="o">=</span> <span class="n">result_text</span><span class="p">.</span><span class="n">text</span><span class="p">.</span><span class="n">split</span><span class="p">()</span>
<span class="n">result</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">result_text</span><span class="p">.</span><span class="n">text</span><span class="p">.</span><span class="n">split</span><span class="p">()[</span><span class="o">-</span><span class="mi">2</span><span class="p">])</span>
<span class="n">page_number</span> <span class="o">=</span> <span class="n">math</span><span class="p">.</span><span class="n">ceil</span><span class="p">(</span><span class="n">result</span><span class="o">/</span><span class="mi">30</span><span class="p">)</span>
<span class="k">return</span> <span class="n">page_number</span>
</code></pre></figure>
<p><strong>3. Iterate through pages</strong></p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">def</span> <span class="nf">page_crawler</span><span class="p">(</span><span class="n">keyword</span><span class="p">):</span>
<span class="c1"># input: keyword for job postings
</span> <span class="c1"># output: dataframe of links scraped from each page
</span>
<span class="c1"># page number
</span> <span class="n">page_number</span> <span class="o">=</span> <span class="n">get_page_number</span><span class="p">(</span><span class="n">keyword</span><span class="p">)</span>
<span class="n">job_links</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">page_number</span><span class="p">):</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Loading page {} ...'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">n</span><span class="o">+</span><span class="mi">1</span><span class="p">))</span>
<span class="n">url</span> <span class="o">=</span> <span class="n">base_url</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">keyword</span><span class="p">,</span> <span class="n">n</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span>
<span class="n">driver</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="n">soup</span> <span class="o">=</span> <span class="n">BeautifulSoup</span><span class="p">(</span><span class="n">driver</span><span class="p">.</span><span class="n">page_source</span><span class="p">,</span> <span class="s">'html.parser'</span><span class="p">)</span>
<span class="c1">#extract all job links
</span> <span class="n">links</span> <span class="o">=</span> <span class="n">soup</span><span class="p">.</span><span class="n">find_all</span><span class="p">(</span><span class="s">'a'</span><span class="p">,{</span><span class="s">'class'</span><span class="p">:</span><span class="s">'DvvsL_0 _1p9OP'</span><span class="p">})</span>
<span class="n">job_links</span> <span class="o">+=</span> <span class="n">links</span>
<span class="n">jobs</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">link</span> <span class="ow">in</span> <span class="n">job_links</span><span class="p">:</span>
<span class="n">job_link</span> <span class="o">=</span> <span class="n">link</span><span class="p">[</span><span class="s">'href'</span><span class="p">].</span><span class="n">strip</span><span class="p">().</span><span class="n">split</span><span class="p">(</span><span class="s">'?'</span><span class="p">,</span> <span class="mi">1</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">jobs</span><span class="p">.</span><span class="n">append</span><span class="p">([</span><span class="n">keyword</span><span class="p">,</span> <span class="n">job_link</span><span class="p">]</span> <span class="o">+</span> <span class="n">job_page_scraper</span><span class="p">(</span><span class="n">job_link</span><span class="p">))</span>
<span class="n">result_df</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">jobs</span><span class="p">,</span> <span class="n">columns</span> <span class="o">=</span> <span class="p">[</span><span class="s">'keyword'</span><span class="p">,</span> <span class="s">'link'</span><span class="p">,</span> <span class="s">'job_id'</span><span class="p">,</span> <span class="s">'job_title'</span><span class="p">,</span> <span class="s">'job_expired'</span><span class="p">,</span> <span class="s">'job_confidential'</span><span class="p">,</span> <span class="s">'job_salary_max'</span><span class="p">,</span> <span class="s">'job_salary_max'</span><span class="p">,</span> <span class="s">'job_salary_currency'</span><span class="p">,</span> <span class="s">'company'</span><span class="p">,</span> <span class="s">'job_post_date'</span><span class="p">,</span> <span class="s">'job_internship'</span><span class="p">,</span> <span class="s">'company_website'</span><span class="p">,</span> <span class="s">'company_avgProcessTime'</span><span class="p">,</span> <span class="s">'company_registrationNo'</span><span class="p">,</span> <span class="s">'company_workingHours'</span><span class="p">,</span> <span class="s">'company_facebook'</span><span class="p">,</span> <span class="s">'company_size'</span><span class="p">,</span> <span class="s">'company_dressCode'</span><span class="p">,</span> <span class="s">'company_nearbyLocations'</span><span class="p">,</span> <span class="s">'company_overview'</span><span class="p">,</span> <span class="s">'job_description'</span><span class="p">,</span> <span class="s">'job_summary'</span><span class="p">,</span> <span class="s">'job_requirement_career_level'</span><span class="p">,</span> <span class="s">'job_requirement_fieldOfStudy'</span><span class="p">,</span> <span class="s">'job_requirement_yearsOfExperience'</span><span class="p">,</span> <span class="s">'job_requirement_qualification'</span><span class="p">,</span> <span class="s">'job_requirement_skill'</span><span class="p">,</span> <span class="s">'job_employment_type'</span><span class="p">,</span> <span class="s">'job_languages'</span><span class="p">,</span> <span class="s">'job_benefits'</span><span class="p">,</span> <span class="s">'job_apply_url'</span><span class="p">,</span> <span class="s">'job_location_zipcode'</span><span class="p">,</span> <span class="s">'job_location'</span><span class="p">,</span> <span class="s">'job_country'</span><span class="p">])</span>
<span class="k">return</span> <span class="n">result_df</span>
</code></pre></figure>
<p><strong>4. Time delay to avoid suspicion</strong></p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="kn">import</span> <span class="nn">time</span>
<span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span></code></pre></figure>
<p><strong>5. Scrape relevant data</strong></p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">def</span> <span class="nf">job_page_scraper</span><span class="p">(</span><span class="n">link</span><span class="p">):</span>
<span class="n">url</span> <span class="o">=</span> <span class="s">"https://www.jobstreet.com.my"</span><span class="o">+</span><span class="n">link</span>
<span class="k">print</span><span class="p">(</span><span class="s">"scraping..."</span><span class="p">,</span> <span class="n">url</span><span class="p">)</span>
<span class="n">driver</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="n">soup</span> <span class="o">=</span> <span class="n">BeautifulSoup</span><span class="p">(</span><span class="n">driver</span><span class="p">.</span><span class="n">page_source</span><span class="p">,</span> <span class="s">'html.parser'</span><span class="p">)</span>
<span class="n">scripts</span> <span class="o">=</span> <span class="n">soup</span><span class="p">.</span><span class="n">find_all</span><span class="p">(</span><span class="s">"script"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">script</span> <span class="ow">in</span> <span class="n">scripts</span><span class="p">:</span>
<span class="k">if</span> <span class="n">script</span><span class="p">.</span><span class="n">contents</span><span class="p">:</span>
<span class="n">txt</span> <span class="o">=</span> <span class="n">script</span><span class="p">.</span><span class="n">contents</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">strip</span><span class="p">()</span>
<span class="k">if</span> <span class="s">'window.REDUX_STATE = '</span> <span class="ow">in</span> <span class="n">txt</span><span class="p">:</span>
<span class="n">jsonStr</span> <span class="o">=</span> <span class="n">script</span><span class="p">.</span><span class="n">contents</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">strip</span><span class="p">()</span>
<span class="n">jsonStr</span> <span class="o">=</span> <span class="n">jsonStr</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="s">'window.REDUX_STATE = '</span><span class="p">)[</span><span class="mi">1</span><span class="p">].</span><span class="n">strip</span><span class="p">()</span>
<span class="n">jsonStr</span> <span class="o">=</span> <span class="n">jsonStr</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="s">'}}}};'</span><span class="p">)[</span><span class="mi">0</span><span class="p">].</span><span class="n">strip</span><span class="p">()</span>
<span class="n">jsonStr</span> <span class="o">=</span> <span class="n">jsonStr</span><span class="o">+</span><span class="s">"}}}}"</span>
<span class="n">jsonObj</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="n">loads</span><span class="p">(</span><span class="n">jsonStr</span><span class="p">)</span>
<span class="n">job</span> <span class="o">=</span> <span class="n">jsonObj</span><span class="p">[</span><span class="s">'details'</span><span class="p">]</span>
<span class="n">job_id</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'id'</span><span class="p">]</span>
<span class="n">job_expired</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'isExpired'</span><span class="p">]</span>
<span class="n">job_confidential</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'isConfidential'</span><span class="p">]</span>
<span class="n">job_salary_min</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'header'</span><span class="p">][</span><span class="s">'salary'</span><span class="p">][</span><span class="s">'min'</span><span class="p">]</span>
<span class="n">job_salary_max</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'header'</span><span class="p">][</span><span class="s">'salary'</span><span class="p">][</span><span class="s">'max'</span><span class="p">]</span>
<span class="n">job_salary_currency</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'header'</span><span class="p">][</span><span class="s">'salary'</span><span class="p">][</span><span class="s">'currency'</span><span class="p">]</span>
<span class="n">job_title</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'header'</span><span class="p">][</span><span class="s">'jobTitle'</span><span class="p">]</span>
<span class="n">company</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'header'</span><span class="p">][</span><span class="s">'company'</span><span class="p">][</span><span class="s">'name'</span><span class="p">]</span>
<span class="n">job_post_date</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'header'</span><span class="p">][</span><span class="s">'postedDate'</span><span class="p">]</span>
<span class="n">job_internship</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'header'</span><span class="p">][</span><span class="s">'isInternship'</span><span class="p">]</span>
<span class="n">company_website</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'companyDetail'</span><span class="p">][</span><span class="s">'companyWebsite'</span><span class="p">]</span>
<span class="n">company_avgProcessTime</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'companyDetail'</span><span class="p">][</span><span class="s">'companySnapshot'</span><span class="p">][</span><span class="s">'avgProcessTime'</span><span class="p">]</span>
<span class="n">company_registrationNo</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'companyDetail'</span><span class="p">][</span><span class="s">'companySnapshot'</span><span class="p">][</span><span class="s">'registrationNo'</span><span class="p">]</span>
<span class="n">company_workingHours</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'companyDetail'</span><span class="p">][</span><span class="s">'companySnapshot'</span><span class="p">][</span><span class="s">'workingHours'</span><span class="p">]</span>
<span class="n">company_facebook</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'companyDetail'</span><span class="p">][</span><span class="s">'companySnapshot'</span><span class="p">][</span><span class="s">'facebook'</span><span class="p">]</span>
<span class="n">company_size</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'companyDetail'</span><span class="p">][</span><span class="s">'companySnapshot'</span><span class="p">][</span><span class="s">'size'</span><span class="p">]</span>
<span class="n">company_dressCode</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'companyDetail'</span><span class="p">][</span><span class="s">'companySnapshot'</span><span class="p">][</span><span class="s">'dressCode'</span><span class="p">]</span>
<span class="n">company_nearbyLocations</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'companyDetail'</span><span class="p">][</span><span class="s">'companySnapshot'</span><span class="p">][</span><span class="s">'nearbyLocations'</span><span class="p">]</span>
<span class="n">company_overview</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'companyDetail'</span><span class="p">][</span><span class="s">'companyOverview'</span><span class="p">][</span><span class="s">'html'</span><span class="p">]</span>
<span class="n">job_description</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'jobDetail'</span><span class="p">][</span><span class="s">'jobDescription'</span><span class="p">][</span><span class="s">'html'</span><span class="p">]</span>
<span class="n">job_summary</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'jobDetail'</span><span class="p">][</span><span class="s">'summary'</span><span class="p">]</span>
<span class="n">job_requirement_career_level</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'jobDetail'</span><span class="p">][</span><span class="s">'jobRequirement'</span><span class="p">][</span><span class="s">'careerLevel'</span><span class="p">]</span>
<span class="n">job_requirement_yearsOfExperience</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'jobDetail'</span><span class="p">][</span><span class="s">'jobRequirement'</span><span class="p">][</span><span class="s">'yearsOfExperience'</span><span class="p">]</span>
<span class="n">job_requirement_qualification</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'jobDetail'</span><span class="p">][</span><span class="s">'jobRequirement'</span><span class="p">][</span><span class="s">'qualification'</span><span class="p">]</span>
<span class="n">job_requirement_fieldOfStudy</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'jobDetail'</span><span class="p">][</span><span class="s">'jobRequirement'</span><span class="p">][</span><span class="s">'fieldOfStudy'</span><span class="p">]</span>
<span class="c1">#job_requirement_industry = job['jobDetail']['jobRequirement']['industryValue']['label']
</span> <span class="n">job_requirement_skill</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'jobDetail'</span><span class="p">][</span><span class="s">'jobRequirement'</span><span class="p">][</span><span class="s">'skills'</span><span class="p">]</span>
<span class="n">job_employment_type</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'jobDetail'</span><span class="p">][</span><span class="s">'jobRequirement'</span><span class="p">][</span><span class="s">'employmentType'</span><span class="p">]</span>
<span class="n">job_languages</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'jobDetail'</span><span class="p">][</span><span class="s">'jobRequirement'</span><span class="p">][</span><span class="s">'languages'</span><span class="p">]</span>
<span class="n">job_benefits</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'jobDetail'</span><span class="p">][</span><span class="s">'jobRequirement'</span><span class="p">][</span><span class="s">'benefits'</span><span class="p">]</span>
<span class="n">job_apply_url</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'applyUrl'</span><span class="p">][</span><span class="s">'url'</span><span class="p">]</span>
<span class="n">job_location_zipcode</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'location'</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="s">'locationId'</span><span class="p">]</span>
<span class="n">job_location</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'location'</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="s">'location'</span><span class="p">]</span>
<span class="n">job_country</span> <span class="o">=</span> <span class="n">job</span><span class="p">[</span><span class="s">'sourceCountry'</span><span class="p">]</span>
<span class="k">return</span> <span class="p">[</span><span class="n">job_id</span><span class="p">,</span> <span class="n">job_title</span><span class="p">,</span> <span class="n">job_expired</span><span class="p">,</span> <span class="n">job_confidential</span><span class="p">,</span> <span class="n">job_salary_max</span><span class="p">,</span> <span class="n">job_salary_max</span><span class="p">,</span> <span class="n">job_salary_currency</span><span class="p">,</span> <span class="n">company</span><span class="p">,</span> <span class="n">job_post_date</span><span class="p">,</span> <span class="n">job_internship</span><span class="p">,</span> <span class="n">company_website</span><span class="p">,</span> <span class="n">company_avgProcessTime</span><span class="p">,</span> <span class="n">company_registrationNo</span><span class="p">,</span> <span class="n">company_workingHours</span><span class="p">,</span> <span class="n">company_facebook</span><span class="p">,</span> <span class="n">company_size</span><span class="p">,</span> <span class="n">company_dressCode</span><span class="p">,</span> <span class="n">company_nearbyLocations</span><span class="p">,</span> <span class="n">company_overview</span><span class="p">,</span> <span class="n">job_description</span><span class="p">,</span> <span class="n">job_summary</span><span class="p">,</span> <span class="n">job_requirement_career_level</span><span class="p">,</span> <span class="n">job_requirement_fieldOfStudy</span><span class="p">,</span> <span class="n">job_requirement_yearsOfExperience</span><span class="p">,</span> <span class="n">job_requirement_qualification</span><span class="p">,</span> <span class="n">job_requirement_skill</span><span class="p">,</span> <span class="n">job_employment_type</span><span class="p">,</span> <span class="n">job_languages</span><span class="p">,</span> <span class="n">job_benefits</span><span class="p">,</span> <span class="n">job_apply_url</span><span class="p">,</span> <span class="n">job_location_zipcode</span><span class="p">,</span> <span class="n">job_location</span><span class="p">,</span> <span class="n">job_country</span><span class="p">]</span></code></pre></figure>
<p><strong>6. save data</strong></p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c1"># concatenate dataframes and save scraped information as csv
</span><span class="n">pd</span><span class="p">.</span><span class="n">concat</span><span class="p">(</span><span class="n">dfs</span><span class="p">).</span><span class="n">to_csv</span><span class="p">(</span><span class="s">"job_postings_results.csv"</span><span class="p">)</span></code></pre></figure>
</content>
<summary>Each website is built by different individuals so there is no one magic script that can scrape different websites because the art of scraping lies in deconstructing the html elements into separate objects that we can extract or “scrape” the information from. Of course there are scraping tools out there that automate these scripts based on your preference (literally google free web scraping tools, there are a bunch of them). I have tried several of these tools and I always end up getting frustrated and going back to writing the codes myself because a) they always have a pricing tier despite claiming to be free, and b) the process is overcomplicated and some websites are just not built intuitively that these tools can easily automate. This tutorial specifies the necessary steps to scrape data from Jobstreet Malaysia but the process of crawling and scraping boils down to a few basic steps that can be applied to almost any website.</summary>
</entry>
<entry>
<title>Tokyo State of Mind</title>
<id>http://0.0.0.0:4321/tokyo-state-of-mind.html</id>
<link rel="alternate" type="text/html" href="http://0.0.0.0:4321/tokyo-state-of-mind.html" />
<published>2020-12-24T00:00:00+08:00</published>
<updated>2021-04-15T23:42:55+08:00</updated>
<author>
<name>Naelah Nordin</name>
<uri>https://naelahnordin.com/</uri>
<email>naelahnordin@gmail.com</email>
</author>
<content type="html" xml:base="http://0.0.0.0:4321/">
<p>Sometimes people ask me how was it like in Japan? And I often find it hard to answer because my experience with Japan spans a few years starting when my dad worked there for a couple of years</p>
<p>When I try to recall Japan, I get flashes of memories. Getting on the wrong express train platform and going the opposite direction and trying to go on the right direction but realizing too late that express trains and normal trains share the same tracks and a supposedly 1 hour trip ended up being 3 hours. Seeing my dad after a year and seeing how his wrinkles are more prominent and his hair is turning whiter and it hit me how much time spent apart is time wasted not being together.</p>
<h2 id="the-process">The Process</h2>
<p>The process of marriage is very simple. Boy meets girl. Boy &amp; girl like each other. Boy meets girl’s parents. Register marr</p>
<h2 id="the-process-1">The Process</h2>
<h2 id="the-problem">The Problem</h2>
</content>
<summary>Sometimes people ask me how was it like in Japan? And I often find it hard to answer because my experience with Japan spans a few years starting when my dad worked there for a couple of years</summary>
</entry>
<entry>
<title>Visualizing Malaysian Cinema</title>
<id>http://0.0.0.0:4321/visualizing-malaysian-cinema.html</id>
<link rel="alternate" type="text/html" href="http://0.0.0.0:4321/visualizing-malaysian-cinema.html" />
<published>2020-11-12T00:00:00+08:00</published>
<updated>2021-04-15T23:46:41+08:00</updated>
<author>
<name>Naelah Nordin</name>
<uri>https://naelahnordin.com/</uri>
<email>naelahnordin@gmail.com</email>
</author>
<content type="html" xml:base="http://0.0.0.0:4321/">
<!-- ---
layout: post
title: Visualizing 20 years of Malay Cinema
#category: projects
tags: projects, data visualization, d3.js
desc: Using Apply lambda function to loop through each row in a dataframe
---
## The Problem -->
</content>
<summary>&lt;!– —layout: posttitle: Visualizing 20 years of Malay Cinema#category: projectstags: projects, data visualization, d3.jsdesc: Using Apply lambda function to loop through each row in a dataframe—</summary>
</entry>
<entry>
<title>Ebilikguru</title>
<id>http://0.0.0.0:4321/eBilikGuru.html</id>
<link rel="alternate" type="text/html" href="http://0.0.0.0:4321/eBilikGuru.html" />
<published>2020-10-01T00:00:00+08:00</published>
<updated>2021-04-15T23:45:20+08:00</updated>
<author>
<name>Naelah Nordin</name>
<uri>https://naelahnordin.com/</uri>
<email>naelahnordin@gmail.com</email>
</author>
<content type="html" xml:base="http://0.0.0.0:4321/">
</content>
<summary></summary>
</entry>
<entry>
<title>Aduh pothole reporting app</title>
<id>http://0.0.0.0:4321/Aduh-Pothole-Reporting-App.html</id>
<link rel="alternate" type="text/html" href="http://0.0.0.0:4321/Aduh-Pothole-Reporting-App.html" />
<published>2020-09-30T00:00:00+08:00</published>
<updated>2021-04-15T23:45:15+08:00</updated>
<author>
<name>Naelah Nordin</name>
<uri>https://naelahnordin.com/</uri>
<email>naelahnordin@gmail.com</email>
</author>
<content type="html" xml:base="http://0.0.0.0:4321/">
</content>
<summary></summary>
</entry>
<entry>
<title>Mapping Two Dataframes In Python</title>
<id>http://0.0.0.0:4321/mapping-two-dataframes-in-python.html</id>
<link rel="alternate" type="text/html" href="http://0.0.0.0:4321/mapping-two-dataframes-in-python.html" />
<published>2020-09-20T00:00:00+08:00</published>
<updated>2021-04-15T23:46:33+08:00</updated>
<author>
<name>Naelah Nordin</name>
<uri>https://naelahnordin.com/</uri>
<email>naelahnordin@gmail.com</email>
</author>
<content type="html" xml:base="http://0.0.0.0:4321/">
<!-- ---
layout: post
title: Mapping Data in Python
#category: notes
tags: notes, python, programming, pandas, dataframe, mapping
desc: Mapping two dataframes with a matching value in a single column
---
## The Problem
You have two dataframes with a single column that links both with common data. For example a dataframe containing
```python
```
## The Solution
-->
</content>
<summary>&lt;!– —layout: posttitle: Mapping Data in Python#category: notestags: notes, python, programming, pandas, dataframe, mappingdesc: Mapping two dataframes with a matching value in a single column</summary>
</entry>
<entry>
<title>Iterations in Python</title>
<id>http://0.0.0.0:4321/using-apply-lambda-in-python.html</id>
<link rel="alternate" type="text/html" href="http://0.0.0.0:4321/using-apply-lambda-in-python.html" />
<published>2020-08-01T00:00:00+08:00</published>
<updated>2021-04-16T13:11:20+08:00</updated>
<author>
<name>Naelah Nordin</name>
<uri>https://naelahnordin.com/</uri>
<email>naelahnordin@gmail.com</email>
</author>
<content type="html" xml:base="http://0.0.0.0:4321/">
<h1 id="using-apply-for-single-column">Using apply for single column</h1>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">df</span><span class="p">[</span><span class="s">'new_column] = df['</span><span class="n">column</span><span class="s">'].apply(lambda x: something(x))</span></code></pre></figure>
<h1 id="using-apply-for-a-whole-row">Using apply for a whole row</h1>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">df</span><span class="p">[</span><span class="s">'new_column] = df['</span><span class="n">column</span><span class="s">'].apply(lambda x: something(x))</span></code></pre></figure>
<h1 id="fixed-iteration">Fixed iteration</h1>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">df</span><span class="p">[</span><span class="s">'new_column] = df['</span><span class="n">column</span><span class="s">'].apply(lambda x: something(x))</span></code></pre></figure>
<h1 id="having-index-of-row">Having index of row</h1>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">df</span><span class="p">[</span><span class="s">'new_column] = df['</span><span class="n">column</span><span class="s">'].apply(lambda x: something(x))</span></code></pre></figure>
</content>
<summary>Using apply for single column</summary>
</entry>
<entry>
<title>The Royal Wedding</title>
<id>http://0.0.0.0:4321/the-royal-wedding.html</id>
<link rel="alternate" type="text/html" href="http://0.0.0.0:4321/the-royal-wedding.html" />
<published>2018-04-01T00:00:00+08:00</published>
<updated>2021-04-15T23:43:22+08:00</updated>
<author>
<name>Naelah Nordin</name>
<uri>https://naelahnordin.com/</uri>
<email>naelahnordin@gmail.com</email>
</author>
<content type="html" xml:base="http://0.0.0.0:4321/">
<p>Getting married is a big step into adulthood. It’s not quite a big deal depending on your circumstances but it’s a huge life decision. Nevertheless it could be the easiest decision you ever make.
You look at a person and you go, “I don’t mind spending my life with that person.” Spending time together feels easy, being in each other’s presence is effortless and you’re both co-existing in each other’s spaces without wanting or needing something in return. You simply exist.</p>
<p>I’m an introvert so physical social interactions normally exhaust me after a certain period of time. There are times even when I felt like hanging out is a chore so if I want to hangout with you, that’s a big deal. If I want to spend the rest of my life with you, that’s mega big deal 5000. Regardless, finding a person you can live with is just one variable of the whole equation. There’s so many hoops and loops to jump through to get in that binding contract and as much as it was worth every effort, it was still pretty damn exhausting. Getting legally married is one thing but planning the wedding reception is a whole different monstrosity altogether.</p>
<h2 id="the-process">The Process</h2>
<p>The process of marriage is very simple. Boy meets girl. Boy &amp; girl like each other. Boy meets girl’s parents. Register marr</p>
<h2 id="the-process-1">The Process</h2>
<h2 id="the-problem">The Problem</h2>
</content>
<summary>Getting married is a big step into adulthood. It’s not quite a big deal depending on your circumstances but it’s a huge life decision. Nevertheless it could be the easiest decision you ever make. You look at a person and you go, “I don’t mind spending my life with that person.” Spending time together feels easy, being in each other’s presence is effortless and you’re both co-existing in each other’s spaces without wanting or needing something in return. You simply exist.</summary>
</entry>
<entry>
<title>Game Addiction Diagnosis User Interface</title>
<id>http://0.0.0.0:4321/Game-Addiction-Diagnosis-User-Interface.html</id>
<link rel="alternate" type="text/html" href="http://0.0.0.0:4321/Game-Addiction-Diagnosis-User-Interface.html" />
<published>2017-10-12T00:00:00+08:00</published>
<updated>2021-04-15T23:45:11+08:00</updated>
<author>
<name>Naelah Nordin</name>
<uri>https://naelahnordin.com/</uri>
<email>naelahnordin@gmail.com</email>
</author>
<content type="html" xml:base="http://0.0.0.0:4321/">
</content>
<summary></summary>
</entry>
</feed>